C casting double ->long -> short (使用右移 ">>")
C casting double ->long -> short (using right shift ">>")
我有一个小代码可以进行一些数字转换。我想将一个数字从 double 转换为 long,然后使用右位移位将其转换为 short。但它给了我不同的结果,我不知道为什么。
我在一个数组中有 3 个数字,我使用 for
循环对它们求和,每次我都将结果转换为 short
。
有一个数字 .000000007
更准确地说 63897600.000000007
。将其添加到总数中然后减去它会得到不同的结果。
我不明白为什么会发生这种情况,我该如何处理这种特殊情况。
这是我的代码:
#include <stdio.h>
#define DOUBLETOLONG(number) (long)(number)
#define NEAREST(number) ((short)((number + 32768) >> 16))
#define LONGTOSHORT(number) NEAREST(DOUBLETOLONG(number))
int main() {
int k = 0;
double array[3] ={ 41451520.000000, 63897600.000000007, -63897600.000000007 };
double total_x = array[0];
short j = LONGTOSHORT(total_x);
printf("j = %d\n", j);
for (k = 1; k < 3; k++) {
total_x = total_x+array[k];
j = LONGTOSHORT(total_x);
printf("j = %d\n", j);
}
return 0;
}
这是结果:
j = 633
j = 1608
j = 632
41451520 + 63897600 = 105349120
在double
中这个整数还是可以准确表示的。但是,我们没有考虑小数部分 0.000000007
。让我们看看下一个最大的 double
是什么:
#include <stdio.h>
#include <math.h>
int main(int argc, char** argv) {
printf("%.23f\n", nextafter(105349120.0, INFINITY));
return 0;
}
原来是 105349120.000000014901...
。让我们把它们放在一起:
105349120.000000014901...
0.000000007
这意味着 105349120.000000007
比下一个更大的 double
更接近 105349120
,因此它正确地向下舍入为 105349120
。
然而,当我们再次减去时,105349120 - 63897600.000000007
会向下舍入,因为下一个比 41451520
更小的双精度数是 (nextafter(41451520.0, 0)
) 41451519.999999992549...
。将它们并排放置:
41451519.999999992549...
41451519.999999993
是的,比 41451520
本身更接近 41451520
下面的第一个双倍。所以它正确地向下舍入为 41451519.999999992549...
.
当您将 41451519.999999992549...
转换为整数时,它 乘以 数字,结果比您预期的少一。
浮点数学充满了惊喜。您应该阅读 What Every Computer Scientist Should Know About Floating-Point Arithmetic,但它现在可能还太高级了。但重要的是要知道,是的,浮点数充满了惊喜,但它不是魔法,你可以从中学习陷阱。
我有一个小代码可以进行一些数字转换。我想将一个数字从 double 转换为 long,然后使用右位移位将其转换为 short。但它给了我不同的结果,我不知道为什么。
我在一个数组中有 3 个数字,我使用 for
循环对它们求和,每次我都将结果转换为 short
。
有一个数字 .000000007
更准确地说 63897600.000000007
。将其添加到总数中然后减去它会得到不同的结果。
我不明白为什么会发生这种情况,我该如何处理这种特殊情况。
这是我的代码:
#include <stdio.h>
#define DOUBLETOLONG(number) (long)(number)
#define NEAREST(number) ((short)((number + 32768) >> 16))
#define LONGTOSHORT(number) NEAREST(DOUBLETOLONG(number))
int main() {
int k = 0;
double array[3] ={ 41451520.000000, 63897600.000000007, -63897600.000000007 };
double total_x = array[0];
short j = LONGTOSHORT(total_x);
printf("j = %d\n", j);
for (k = 1; k < 3; k++) {
total_x = total_x+array[k];
j = LONGTOSHORT(total_x);
printf("j = %d\n", j);
}
return 0;
}
这是结果:
j = 633
j = 1608
j = 632
41451520 + 63897600 = 105349120
在double
中这个整数还是可以准确表示的。但是,我们没有考虑小数部分 0.000000007
。让我们看看下一个最大的 double
是什么:
#include <stdio.h>
#include <math.h>
int main(int argc, char** argv) {
printf("%.23f\n", nextafter(105349120.0, INFINITY));
return 0;
}
原来是 105349120.000000014901...
。让我们把它们放在一起:
105349120.000000014901...
0.000000007
这意味着 105349120.000000007
比下一个更大的 double
更接近 105349120
,因此它正确地向下舍入为 105349120
。
然而,当我们再次减去时,105349120 - 63897600.000000007
会向下舍入,因为下一个比 41451520
更小的双精度数是 (nextafter(41451520.0, 0)
) 41451519.999999992549...
。将它们并排放置:
41451519.999999992549...
41451519.999999993
是的,比 41451520
本身更接近 41451520
下面的第一个双倍。所以它正确地向下舍入为 41451519.999999992549...
.
当您将 41451519.999999992549...
转换为整数时,它 乘以 数字,结果比您预期的少一。
浮点数学充满了惊喜。您应该阅读 What Every Computer Scientist Should Know About Floating-Point Arithmetic,但它现在可能还太高级了。但重要的是要知道,是的,浮点数充满了惊喜,但它不是魔法,你可以从中学习陷阱。