

atcoderをやっていたのですが、このcinに1.3と1.2を入力すると、望まない挙動(error出力)が起きます。キャストなどいろいろ試してみたのですが、原因が分かりません。わかる方いましたら、どうかお願いします。

[code]

    #include <iostream>
    using namespace std;
    
    int main(){
        float xy;
        cin>>xy;
        float temp=(xy-(int)xy)*10;
        if((temp>=0)&&(temp<=2)){
            cout<<temp<<"-";
        }
        else if((temp>=3)&&(temp<=6)){
            cout<<temp;
    
        }
        else if ((temp>=7)&&(temp<=9)){
            cout<<temp<<"+";
        }
        else 
        cout<<"error";
        return 0;
    }
    
[/code]


CC BY-SA 4.0
2021-09-01T05:57:42.643
81155
2021-09-04T11:07:04.047
2021-09-01T06:33:37.043
3060
48004
question
c++
float型を扱う際に問題点があります。


変数`temp`は`float`型ですので、机上での計算結果が2.0だったとしてもコンピュータ内の表現では整数の2と一致しないこともあります。  
ですので範囲指定の際に

[code]

    if((temp>=0)&&(temp<=2)){
        cout<<temp<<"-";
    }
    else if((temp>=3)&&(temp<=6)){
    
[/code]

では2から3の間にある値は全てすり抜けてしまいます。

[code]

    else if((temp>2)&&(temp<=6)){
    
[/code]

としてみてください。


CC BY-SA 4.0
2021-09-01T06:55:22.580
81156
2021-09-01T06:55:22.580
9515
81155
answer


最大精度を使用して浮動小数点値を出力し、何が得られるかを確認してください。

[code]

    #include <iostream>
    #include <limits>
    #include <iomanip>
    
    int main () {
        using namespace std;
        
        cout << setprecision(numeric_limits<float>::max_digits10);
        
        const float xy = 1.3f;
        cout << ((xy - (int)xy) * 10) << endl;
    }
    
[/code]

最新のアーキテクチャのほとんどは、浮動小数点型を表すために[IEEE-754](https://ja.wikipedia.org/wiki/IEEE_754)標準を使用しています。

上記のコードを実行すると、アーキテクチャがIEEE-754をサポートしている場合、出力は次のようになります。

[code]

    // プログラム出力
    2.99999952
    
[/code]

ご覧のとおり、この値は2〜3であるため、条件 `(temp >= 3) && (temp <= 6)`は `false`になります。

しかし、これには修正方法があります。

[code]

    #include <iostream>
    #include <cmath>
    
    int main() {
        using namespace std;
    
        float xy;
        cin >> xy;
    
        // 以下では、浮動小数点数が1つの小数で構成されていることを確認します。
        if (floor(xy * 10) == xy * 10) {
            // roundf(...)」は、精度誤差をなくすために、以下の浮動小数点値を丸めるのに使われます。
            float temp = roundf((xy - (int)xy) * 10);
    
            if (temp >= 0 && temp <= 2)
                cout << temp << "-";
            else if (temp >= 3 && temp <= 6)
                cout << temp;
            else if (temp >= 7 && temp <= 9)
                cout << temp << "+";
        }
        else 
            cout << "error";
    }
    
[/code]

上記はプログラム入力 `1.3`に対して正しく機能し、期待通りに`3`を与えます。


CC BY-SA 4.0
2021-09-04T08:16:03.567
82231
2021-09-04T11:07:04.047
2021-09-04T11:07:04.047
48059
48059
81155
answer