C 浮点数的重复递增
我正在看一些遗留代码,这些代码定义了沿轴C 浮点数的重复递增,c,floating-point,C,Floating Point,我正在看一些遗留代码,这些代码定义了沿轴f的一些网格点 int main(){ double f[9]; int i = 0; for (double a = 0; a <= 1; a += 0.125){ f[i++] = a; } } intmain(){ 双f[9]; int i=0; 对于(double a=0;a当使用C编译器进行编译时,该代码可以提供准确的IEEE 754语义或它们的近似值(例如,FLT_EVAL_METHOD>
f
的一些网格点
int main(){
double f[9];
int i = 0;
for (double a = 0; a <= 1; a += 0.125){
f[i++] = a;
}
}
intmain(){
双f[9];
int i=0;
对于(double a=0;a当使用C编译器进行编译时,该代码可以提供准确的IEEE 754语义或它们的近似值(例如,FLT_EVAL_METHOD>0,甚至子表达式的任意超额精度和任意舍入到标称精度)
你担心的问题是:
表示错误,其中0.125
不完全是1/8,以及
操作错误,其中+
不完全是数学加法。这些都不会发生在这个特定的程序中
0.125要求1位精度以基数2精确表示。这意味着程序在这些条件下使用的浮点数正好是预期的1/8。此外,在加法中存在任何近似值之前,可以将其自身相加253次
此推理不适用于其他增量步骤。例如,以下程序的变体使数组的一个索引f[100]
,至少未使用我的编译器(实现严格的IEEE 754语义)初始化:
intmain(){
双f[101];
int i=0;
对于(双a=0;aC标准保留浮点数实现的行为,许多编译器使用IEEE 754标准。您的代码不正常,因为:
您的代码必须使用IEEE 754标准或具有相同行为的类似标准编译
很难阅读。当你阅读代码时,确切的行为并不明显
这不是在C中迭代数组的正确方法
想象一下,有人不知道该要求,并且不使用IEEE 754标准编译。行为可能完全不同。例如,您的代码可能会产生越界,而这是未定义的行为,您的程序可能会崩溃
也就是说,当使用IEEE 754标准编译时,具有与您的代码相同行为的代码示例:
#include <stddef.h>
int main(void) {
double f[9];
size_t const size_f = sizeof f / sizeof *f;
double a = 0;
for (size_t i = 0; i < size_f; i++) {
f[i] = a;
a += 0.125;
}
}
#包括
内部主(空){
双f[9];
size\t const size\u f=sizeof f/sizeof*f;
双a=0;
对于(大小i=0;i
是的,这太糟糕了,你应该总是使用数组边界进行迭代-其他所有事情都会带来麻烦其他人所说的都是100%正确的。也就是说,值得指出的是0.125是2的精确幂,所以这段代码在任何非深奥的平台上都能正常工作。不,这段代码不好,因为它不明显。“在最初的版本中,double a是在循环之外声明的,我正在阅读原因。”如果我没记错的话,在C99之前,您必须这样做。这非常令人放心。感谢您的回答。虽然您的答案完全正确,但我希望看到一些人提到它绝对不是好代码。在(可能是理论上的)使用BCD算术和表示法的机器,很可能无法工作,例如增量为1/10而不是1/8时,也无法工作。编写一个循环,使其以一个增量而不是另一个增量正常工作是不好的做法。@tofro我避免讨论StackOverflow的样式,但事实上在程序中只调用几个常量,似乎是无意的,使它停止了预期的工作。我添加了一个例子。另一种可能的错误,对f
的越界写入,需要一个循环,需要更多的迭代(累积的错误必须与增量相当)@Stargateur如果你不理解浮点运算的原理,那就错了。你也可以对(inti=0;i!=200;i+=2)说…
是错误的,应该使用@Stargateur注意,您将我的答案中的句子缩短了。还要注意声明int x=40000;
具有实现定义的行为。虽然在任何符合标准的编译器上编写行为相同的代码并非不可能,但这样的练习类似于在一种深奥的语言。在实践中,没有一段重要的C代码不依赖于实现定义的行为。所以所有的否决票,都是循环使用double
来填充数组的人吗?我可以接受。
...
9.8000000000000065e-01 98
9.9000000000000066e-01 99
#include <stddef.h>
int main(void) {
double f[9];
size_t const size_f = sizeof f / sizeof *f;
double a = 0;
for (size_t i = 0; i < size_f; i++) {
f[i] = a;
a += 0.125;
}
}