诸如“为什么不是0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 = 0.8?”之类的问题让我想到......
...让编译器警告浮点常量可能会很好,它会在二进制浮点类型中舍入到最接近的可表示形式(例如,0.1和0.8在基数-2浮点数中舍入,否则他们需要无限量的空间来存储无数个数字。)
我查找了gcc警告,到目前为止找不到这个警告(-Wall
,-Wextra
,-Wfloat-equal
,-Wconversion
,-Wcoercion
(不支持或仅限C?),-Wtraditional
(仅限C)似乎没有做我想做的事。)
我在Microsoft Visual C ++编译器中也没有发现这样的警告。
我错过了隐藏或很少使用的选项吗?
是否有任何具有此类警告的编译器?
编辑:此警告可用于教育目的,并提醒那些新手到浮动点。
答案 0 :(得分:7)
没有技术原因编译器无法发出此类警告。但是,它们只对学生有用(他们应该在他们开始做任何认真工作之前应该教他们浮点运算是如何工作的)以及那些用浮点数做很好工作的人。不幸的是,大多数浮点工作都是粗糙的;人们在计算机上抛出数字而不太关心计算机的工作原理,他们接受任何结果。
默认情况下,警告必须关闭以支持大量现有浮点代码。如果它可用,我会在Mac OS X数学库中为我的代码打开它。当然,库中有一些点依赖于浮点值的每一位,例如我们使用扩展精度算术的地方,并且值在多个浮点对象中表示(例如,我们将有一个具有1 /π的高位的对象,具有1 /π减去第一个对象的另一个对象,以及具有1 /π减去前两个对象的第三个对象,给出大约150位的1 /π)。一些此类值在源文本中以十六进制浮点表示,以避免编译器转换十进制数字时出现任何问题,并且我们可以轻松转换任何剩余数字以避免新编译器警告。
但是,我怀疑我们是否可以说服编译器开发人员有足够的人使用此警告,或者它会捕获足够的错误以使其值得花时间。考虑一下libm的情况。假设我们通常为所有常数编写精确数字,但有一次,写了一些其他数字。这个警告会发现错误吗?那么,有什么bug?最有可能的是,数字被转换为我们想要的值。在编写带有此警告的代码时,我们可能会考虑如何执行浮点计算,并且我们编写的值是适合我们目的的值。例如,它可能是我们计算的某个极小极大多项式的系数,并且系数与它将获得的一样好,无论是近似以十进制表示还是转换为一些可精确表示的十六进制浮点数。
因此,此警告很少会发现错误。也许它会遇到一个错误输入数字的场合,意外地将一个额外的数字插入十六进制浮点数字,使其超出可表示的有效数字。但这种情况很少见。在大多数情况下,我们使用的数字既简单又简短,或者从计算它们的软件中复制和粘贴。在某些情况下,我们会手动输入特殊值,例如0x1.fffffffffffffp0。额外的“f”滑入该数字时的警告可能会在编译期间发现错误,但在测试中几乎肯定会发现该错误,因为它会大大改变特殊值。
因此,这样的编译器警告几乎没有用处:很少有人会使用它,并且它会为使用它的人捕获很少的错误。
答案 1 :(得分:2)
没有这样的编译器开关,原因很明显。 我们用十进制写下二进制组件:
第一小数位是0.5
第二小数位是0.25
第三小数位是0.125
...
你看到了吗?由于数字5 的每个位需要奇数结尾 另一个小数来表示它。一位需要一位小数,两位 需要两位小数,依此类推。因此,对于小数浮点数,这意味着大多数十进制数 单精度浮点数需要24(!)十进制数字 双精度的53(!!)十进制数字。 更糟糕的是,完全数字不携带额外信息,它们是纯文物 由基数变化引起的。
没有人会写下来3.141592653589793115997963468544185161590576171875 为pi避免编译器警告。
答案 2 :(得分:1)
警告在源中:当您撰写float
,double
或long double
时,包括他们各自的文字。显然,一些文字是准确的,但即使这没有多大帮助:两个精确值的总和可能不精确,例如,如果它具有相当不同的尺度。让编译器警告不精确的浮点常量会产生错误的安全感。另外,你对圆形常数的意图是什么?明确地写出确切的最接近的值将容易出错并且模糊了意图。以不同方式编写它们,例如,编写1.0 / 10.0
而不是0.1
也会混淆意图并产生不同的值。
答案 3 :(得分:-1)
我没有看到编译器如何知道或编译器可以警告你这样的事情。只是一个巧合,一个数字可以用本质上不准确的东西来准确表示。