我有一个使用floats
或doubles
执行某些计算的算法。
示例:
double a;
double b;
double c;
...
double result = c / (b - a);
if ((result > 0) && (result < small_number))
{
// result is relevant...
} else {
// result not required...
}
现在,我担心(b - a)
可能为零。如果它接近于零而不是零,则无关紧要,因为result
将超出范围有用,并且我已经检测到(当(b - a)
接近零时,result
将接近+/- inf,这不在0
- small_number
范围内......)
但如果(b - a)
的结果恰好为零,我预计由于除以零会发生某些平台依赖。我可以将if
语句更改为:
if ((!((b-a) == 0.0)) && ((result = c/(b-a)) > 0) && (result < small_number)) {
但我不知道(b-a) == 0.0
是否始终会检测到零的相等性。我已经看到浮点数中存在多个精确零点的表示形式?如何在不进行ε检查的情况下测试它们,我不需要(在我的算法中会忽略一个小的epsilon)?
什么是独立的平台检查方式?
修改
不确定人们是否足够清楚。基本上我想知道如何找到如下表达式:
double result = numerator / denominator;
将导致浮点异常,cpu异常,来自操作系统的信号或其他内容....没有实际执行操作并查看它是否会“抛出”...因为检测到“抛出”这种性质似乎是复杂的和平台特定的。
( (denominator==0.0) || (denominator==-0.0) ) ? "Will 'throw'" : "Won't 'throw'";
是否足够?
答案 0 :(得分:9)
这取决于b
和a
获取其值的方式。零具有浮点格式的精确表示,但更大的问题是几乎 - 但不是非常零的值。检查始终是安全的:
if (abs(b-a) > 0.00000001 && ...
0.00000001是值得的值。
答案 1 :(得分:4)
以下是您的操作方法:检查
,而不是检查(result < small_number)
(abs(c) < abs(b - a) * small_number)
然后你所有的麻烦都消失了!如果通过此测试,c/(b-a)
的计算将永远不会溢出。
答案 2 :(得分:2)
我猜你可以使用fpclassify(-0.0) == FP_ZERO
。但这只有在你想检查某人是否确实将某种零值放入float-type变量时才有用。正如许多人已经说过的,如果你想检查计算结果,由于表示的性质,你可能会得到非常接近于零的值。
答案 3 :(得分:0)
更新(2016-01-04)
我收到了一些关于这个答案的downvotes,我想知道我是否应该删除它。似乎共识(https://meta.stackexchange.com/questions/146403/should-i-delete-my-answers)只是在极端情况下才能删除答案。
所以,我的回答是错误的。但我想我会把它放弃,因为它提供了一种有趣的“思考开箱即用”的思想实验。
===============
宾果,
你说你想知道b-a == 0。
另一种看待这种情况的方法是确定a == b。如果a等于b,那么b-a将等于0.
我发现了另一个有趣的想法:
http://www.cygnus-software.com/papers/comparingfloats/Comparing%20floating%20point%20numbers.htm
基本上,你采用你拥有的浮点变量并告诉编译器将它们(一点一滴地)重新解释为有符号整数,如下所示:
if (*(int*)&b == *(int*)&a)
然后你要比较整数,而不是浮点数。也许这会有所帮助?也许不吧。祝你好运!
答案 4 :(得分:0)
我认为(b-a)==0
在c/(b-a)
由于(b-a)
为零而失败的情况下将完全正确。浮动数学是棘手的,但在我看来质疑这是夸大其词。另外,我相信(b-a)==0
将等同于b!=a
。
区分正面和负面0也不是必需的。参见例如这里Does float have a negative zero? (-0f)
答案 5 :(得分:0)
对于epsilon,有一个标准模板定义std :: numeric_limits :: epsilon()。我想检查差异大于std :: numeric_limits :: epsilon()应该足够安全以防止被零除。我猜这里没有平台依赖。
答案 6 :(得分:0)
简而言之,如果我们知道它代表格式,我们就可以知道浮动数字是零。
在实践中,我们将x
与较小的数字进行比较。如果x
小于此数字,我们认为x
与ZERO功能相同(但大部分时间我们的小数仍然大于零)。这种方法非常简单,高效且可以跨平台。
实际上,float
和double
以特殊格式呈现,广泛使用的是当前硬件IEEE 754,将数字划分为符号,指数和尾数(有效数字)位。
因此,如果我们想要检查浮点数是否为 ZERO ,我们可以检查指数和尾数是否为零,请参阅here。
在IEEE 754二进制浮点数中,表示零值 有偏差的指数和有效数都为零。负零 将符号位设置为1。
以float
为例,我们可以编写一个简单的代码来提取指数和尾数位,然后检查它。
#include <stdio.h>
typedef union {
float f;
struct {
unsigned int mantissa : 23;
unsigned int exponent : 8;
unsigned int sign : 1;
} parts;
} float_cast;
int isZero(float num) {
int flag = 0;
float_cast data;
data.f = num;
// Check both exponent and mantissa parts
if(data.parts.exponent == 0u && data.parts.mantissa == 0u) {
flag = 1;
} else {
flag = 0;
}
return(flag);
}
int main() {
float num1 = 0.f, num2 = -0.f, num3 = 1.2f;
printf("\n is zero of %f -> %d", num1, isZero(num1));
printf("\n is zero of %f -> %d", num2, isZero(num2));
printf("\n is zero of %f -> %d", num3, isZero(num3));
return(0);
}
测试结果:
#是0.000000的零 - &gt; 1
#是-0.000000的零 - &gt; 1
#是1.200000的零 - &gt; 0
更多示例:
让我们检查float
何时成为真正的ZERO代码。
void test() {
int i =0;
float e = 1.f, small = 1.f;
for(i = 0; i < 40; i++) {
e *= 10.f;
small = 1.f/e;
printf("\nis %e zero? : %d", small, isZero(small));
}
return;
}
is 1.0000e-01 zero? : NO
is 1.0000e-02 zero? : NO
is 1.0000e-03 zero? : NO
is 1.0000e-04 zero? : NO
is 1.0000e-05 zero? : NO
is 1.0000e-06 zero? : NO
is 1.0000e-07 zero? : NO
is 1.0000e-08 zero? : NO
is 1.0000e-09 zero? : NO
is 1.0000e-10 zero? : NO
is 1.0000e-11 zero? : NO
is 1.0000e-12 zero? : NO
is 1.0000e-13 zero? : NO
is 1.0000e-14 zero? : NO
is 1.0000e-15 zero? : NO
is 1.0000e-16 zero? : NO
is 1.0000e-17 zero? : NO
is 1.0000e-18 zero? : NO
is 1.0000e-19 zero? : NO
is 1.0000e-20 zero? : NO
is 1.0000e-21 zero? : NO
is 1.0000e-22 zero? : NO
is 1.0000e-23 zero? : NO
is 1.0000e-24 zero? : NO
is 1.0000e-25 zero? : NO
is 1.0000e-26 zero? : NO
is 1.0000e-27 zero? : NO
is 1.0000e-28 zero? : NO
is 1.0000e-29 zero? : NO
is 1.0000e-30 zero? : NO
is 1.0000e-31 zero? : NO
is 1.0000e-32 zero? : NO
is 1.0000e-33 zero? : NO
is 1.0000e-34 zero? : NO
is 1.0000e-35 zero? : NO
is 1.0000e-36 zero? : NO
is 1.0000e-37 zero? : NO
is 1.0000e-38 zero? : NO
is 0.0000e+00 zero? : YES <-- 1e-39
is 0.0000e+00 zero? : YES <-- 1e-40
答案 7 :(得分:-1)
你可以尝试
if ((b-a)!=(a-b) && ((result = c/(b-a)) > 0) && (result < small_number))) {
...