質問

Intel マシンで次の C コードを実行すると...

float f = -512;
unsigned char c;

while ( f < 513 )
{
    c = f;
    printf( "%f -> %d\n", f, c );
    f += 64;
}

...出力は次のようになります。

-512.000000 -> 0
-448.000000 -> 64
-384.000000 -> 128
-320.000000 -> 192
-256.000000 -> 0
-192.000000 -> 64
-128.000000 -> 128
-64.000000 -> 192
0.000000 -> 0
64.000000 -> 64
128.000000 -> 128
192.000000 -> 192
256.000000 -> 0
320.000000 -> 64
384.000000 -> 128
448.000000 -> 192
512.000000 -> 0

ただし、同じコードを ARM デバイス (私の場合は iPad) で実行すると、結果はまったく異なります。

-512.000000 -> 0
-448.000000 -> 0
-384.000000 -> 0
-320.000000 -> 0
-256.000000 -> 0
-192.000000 -> 0
-128.000000 -> 0
-64.000000 -> 0
0.000000 -> 0
64.000000 -> 64
128.000000 -> 128
192.000000 -> 192
256.000000 -> 0
320.000000 -> 64
384.000000 -> 128
448.000000 -> 192
512.000000 -> 0

ご想像のとおり、この種の違いにより、 最悪 クロスプラットフォームプロジェクトのバグ。私の質問は次のとおりです。

  1. float を unsigned char に強制すると、すべてのプラットフォームで同じ結果が得られると想定したのは間違いでしたか?

  2. コンパイラに問題があるのでしょうか?

  3. エレガントな回避策はありますか?

役に立ちましたか?

解決

C標準には、あなたがやろうとしていることに対する非常に難しいルールはありません。これが、セクションから問題の段落です 6.3.1算術オペランド (具体的にはセクション 6.3.1.4実際のフローティングと整数):

実際のフローティングタイプの有限値が以外の整数型に変換される場合 _Bool, 、分数部分は破棄されます(つまり、値はゼロに切り捨てられます)。積分部分の値を整数型で表すことができない場合、動作は未定義です。

あなたが尋ねている正確なケースについてより具体的な脚注さえあります:

整数タイプの値が符号なしタイプに変換されたときに実行される残りの操作は、実際のフローティングタイプの値が符号なしタイプに変換された場合に実行する必要はありません。したがって、ポータブルな実際の浮動値の範囲は (−1, Utype_MAX+1).

UtypeMAX+1 あなたの場合はそうです 256. 。あなたの不一致のケースはすべて負の数です。切り捨ての後、それらはまだネガティブであり、範囲外(-1、256)の外側にあるため、「未定義の動作」ゾーンにしっかりといます。あなたが示した一致するケースのいくつかでさえ、浮動小数点数が大きいか等しい 256, 、仕事が保証されていません - あなたはただ幸運になっています。

したがって、番号付きの質問に対する回答:

  1. はい、あなたは間違っていました。
  2. さまざまなコンパイラが異なる結果をもたらすという意味でのコンパイラの問題ですが、スペックで許可されているため、コンパイラのせいとは呼びません。
  3. それはあなたがやりたいことに依存します - あなたがそれをより良く説明できるならば、コミュニティの誰かがあなたを助けることができるとほぼ確実です。

他のヒント

私は自分の質問で3に答えるつもりですが、受け入れられた答えとしてそれにフラグを立てません。トリックは、強制の単純なキャストのようです:

c = (char) f;

(int)または(short)worksも使用します。この問題の原因がどこにあるのかを知りたいと思っています:コンパイラまたはプロセッサ。

あなたが扱っている特定の問題は、私にはエンディアンのように見えます。いずれかの実装を次のものに置き換えてみてください c = *((char *)&f + sizeof(float) - 1); または同様の方法で float の最後のバイトを取得し、それが他のプラットフォームの結果と一致するかどうかを確認します。

一般に、動作はプロセッサのエンディアン、ワード長、浮動小数点機能、およびコンパイラがそれをどのようにターゲットにするかによって異なります。ARM はバイエンディアンであるため、IA のバイト順序と一致する場合と一致しない場合があります。ある C 実装が別の C 実装と同じ浮動小数点形式をサポートするという一般的な保証もないようです。 固定サイズの浮動小数点型 .

これを実稼働コードで使用していますか?なぜこれを行う必要があるのか​​を徹底的に検討したいと思います。どちらかのタイプが意図したとおりに使用されていない可能性があります。回避策は洗練されたものではありません。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top