完全に正当なシステムであるこのコンパイラでは、整数のサイズは 16 ビットでなければなりません。
443118 になると予想xk1
しました。443118 % 65536 は 49902 です。
計算以来:
unsigned short int xk=3588, yk=47541, yk1, sig=10, de=1;
unsigned long int xk1;
xk1=( xk+(sig*(yk-xk)*de));
が値のみを含むunsigned short
場合、これらは に昇格されunsigned int
、結果が として計算され、unsigned int
最後にその値が に割り当てられますunsigned long
。しかし、余分なビットはずっと前に失われました...計算は16ビットの符号なし算術演算で行われました。
実験
GCC 4.1.2 を搭載した 64 ビット RHEL5 (AMD x86/64) マシンで実施。16 ビット整数の計算をシミュレートするために、式に((unsigned short)(...))
キャストを自由に組み合わせました (2 番目のコピー)。二重乗算は単一のキャストのみを取得します。2 つの乗算が実行される順序に関係なく、結果は変化しません (被乗数の 1 つが 1 であるため、二重に変化しません)。(unsigned long)
そして、キャスト付きの式 (の 3 番目のコピー) を含めました。
テストプログラム:
#include <stdio.h>
int main(void)
{
unsigned short int xk=3588, yk=47541, sig=10, de=1;
unsigned long int xk1;
xk1 = (xk+(sig*(yk-xk)*de));
printf("No Cast: %6lu = (%u+(%u*(%u-%u)*%u))\n", xk1, xk, sig, yk, xk, de);
xk1 = ((unsigned short)(xk+((unsigned short)(sig*((unsigned short)(yk-xk))*de))));
printf("US Cast: %6lu = (%u+(%u*(%u-%u)*%u))\n", xk1, xk, sig, yk, xk, de);
xk1 = (xk+(sig*((unsigned long)yk-xk)*de));
printf("UL Cast: %6lu = (%u+(%u*(%u-%u)*%u))\n", xk1, xk, sig, yk, xk, de);
return 0;
}
出力は次のとおりです。
$ gcc -Wall -Wextra -g -O3 -std=c99 xx.c -o xx && ./xx
No Cast: 443118 = (3588+(10*(47541-3588)*1))
US Cast: 49902 = (3588+(10*(47541-3588)*1))
UL Cast: 443118 = (3588+(10*(47541-3588)*1))
$
2 番目のほとんど判読できない式は、16 ビット コンパイラが式を評価する方法を正確に反映している (または十分に正確に反映している) と思います。
(47541-3588) の結果は 43953 です。(10 * 43953) % 65536 の結果は 46314 です。3588 を追加すると、結果は当然のことながら 49902 になります。
(unsigned long)
また、式にキャストを追加しyk
て実行しました。おそらく、32 ビットのマシンに完全に忠実にするためにunsigned long
、 を使用する必要がunsigned int
ありましたが、結果は変わりません。あなたが代替価値をどこから得たのかわかりません-それについてのアイデアを得るには、あなたの完全な作業プログラム(私のものと同様)を見る必要があります。計算の一部が「負になる」ように見え、大きな (正の) 符号なし値が残りますが、計算が負になる明らかな言い訳はありません。
コメントからコードを取得します。
#include <stdio.h>
// -unused- #include "uart1.h"
// -unused- #include <stdlib.h>
// -unused- #include <stdint.h>
// -unused- #include <string.h>
// -unused- #include <math.h>
// -unused- int putchar(int c) { return uart1_putchar(c); }
int main(void)
{
//variables
unsigned short int xk=3588, yk=47541, yk1, sig=10, de=1;
unsigned long xk1;
// -not-needed-in-demo uart1_init();
xk1=( xk+(sig*((unsigned long)yk-xk)*de));
yk1=xk1 % 65535;
//printf("xk1=%6lx\t\n,",xk1);
//printf("yk1=%u\t\n,",yk1);
printf("xk1 = %6lx = %6u\n", xk1, xk1);
printf("yk1 = %6x = %6u\n", yk1, yk1);
}
65535 は 65536 である必要があります。行末のタブは不要であり、次の行頭のカンマも不要です (ただし、これらは単なる装飾です)。
より深刻な (ただし、使用されていないため、当面の問題には重要ではあり<stdio.h>
ません) は、 と呼ばれる関数 (通常はマクロも) を定義しますputchar()
。おそらく、 という独自の関数を定義するべきではputchar
ありませんが、そうする必要がある場合は、通常、 からマクロを定義解除する必要があります (マクロがあると仮定します) <stdio.h>
。私のマシンでコードが正常にコンパイルされたことを認めます-リンクしませんでしたが、それは予想されていました。いつの日かputchar()
、このマシンの中身を突き止める日が来るかもしれません。
示されているコードは、正しい/期待される答えを生成します。
観察された不正な動作を生成する唯一の方法は、余分なコードを削除した次のとおりです。
#include <stdio.h>
int main(void)
{
unsigned short int xk=3588, yk=47541, yk1, sig=10, de=1;
unsigned long xk1;
xk1=( xk+(sig*((unsigned long)yk-xk)*de));
yk1=xk1 % 65536;
printf("xk1= %6lx = %6lu\n", xk1, xk1);
printf("yk1= %6x = %6u\n", yk1, yk1);
xk1=( xk+(sig*((short)yk-xk)*de));
yk1=xk1 % 65536;
printf("xk1= %6lx = %6lu\n", xk1, xk1);
printf("yk1= %6x = %6u\n", yk1, yk1);
}
64 ビット マシン (現在、GCC 4.6.0 を搭載した MacOS X 10.6.7) で実行すると、次のようになります。
xk1= 6c2ee = 443118
yk1= c2ee = 49902
xk1= fffffffffffcc2ee = 18446744073709339374
yk1= c2ee = 49902
16 進値の 8 つの余分な F を無視すると、取得している 0xFFF B C2EEではなく、 0xFFF C C2EEが取得されます。私はその矛盾について何の説明もありません。しかし、中間結果が符号付きの 16 ビット量である場合は、見ている結果とほぼ同じ結果になることがわかります。
次に問題は、なぜそこに署名された操作があるのかということです。いい説明がありません。アセンブラコードを見て、何が起こっているのかを理解する必要があると思います。コンパイラのバグをくすぐっているかもしれません。