我有一个double
值f
,想要一个稍微大一点(或更小)的方法,以获得一个尽可能接近原始值的新值,但仍然严格大于(或小于)原件。
它不必靠近最后一位 - 更重要的是,我所做的任何改变都能保证产生不同的值,而不是回到原来的状态。
答案 0 :(得分:61)
检查math.h文件。如果您很幸运,您可以定义nextafter
和nextafterf
个函数。它们以便携式和平台无关的方式完成您想要的工作,并且是C99标准的一部分。
另一种方法(可能是后备解决方案)是将你的浮点数分解为尾数和指数部分。增量很简单:只需在尾数中添加一个即可。如果出现溢出,则必须通过递增指数来处理此问题。减少的方式也是一样的。
编辑:正如评论中指出的那样,只需在其二进制表示中增加浮点数就足够了。尾数溢出将增加指数,这正是我们想要的。
简而言之,这与nextafter相同。
但这不是完全可移植的。您将不得不处理endianess以及并非所有机器都具有IEEE浮动的事实(好的 - 最后一个原因是更具学术性)。
处理NAN和infinite也有点棘手。你不能简单地增加它们,因为它们是定义而不是数字。
答案 1 :(得分:23)
u64 &x = *(u64*)(&f);
x++;
是的,认真的。
编辑:正如有人指出的那样,这并不能正确处理-ve数字,Inf,Nan或溢出。以上更安全的版本是
u64 &x = *(u64*)(&f);
if( ((x>>52) & 2047) != 2047 ) //if exponent is all 1's then f is a nan or inf.
{
x += f>0 ? 1 : -1;
}
答案 2 :(得分:4)
从绝对意义上讲,您可以添加到浮点值以创建新的不同值的最小量将取决于值的当前大小;它将是类型machine epsilon乘以当前指数。
查看IEEE spec的浮点表示。最简单的方法是将值重新解释为整数类型,添加1,然后检查(如果您关心)您没有翻转符号或通过检查符号和指数位生成NaN。
或者,您可以使用frexp来获取当前的尾数和指数,从而计算要添加的值。
答案 3 :(得分:3)
我需要做同样的事情并提出这段代码:
double DoubleIncrement(double value)
{
int exponent;
double mantissa = frexp(value, &exponent);
if(mantissa == 0)
return DBL_MIN;
mantissa += DBL_EPSILON/2.0f;
value = ldexp(mantissa, exponent);
return value;
}
答案 4 :(得分:1)
对于它的价值,标准++增量停止运行的值是9,007,199,254,740,992。
答案 5 :(得分:0)
这可能不是您想要的,但您仍然可能会发现numeric_limits正在使用中。特别是成员min()和epsilon()。
我不相信像mydouble + numeric_limits :: epsilon()这样的东西会做你想要的,除非mydouble已经接近epsilon了。如果是,那么你很幸运。
答案 6 :(得分:-2)
我在一段时间后发现了这段代码,也许它可以帮助你确定最小的你可以将它推高,然后再增加该值。不幸的是我不记得这段代码的参考资料:
#include <stdio.h>
int main()
{
/* two numbers to work with */
double number1, number2; // result of calculation
double result;
int counter; // loop counter and accuracy check
number1 = 1.0;
number2 = 1.0;
counter = 0;
while (number1 + number2 != number1) {
++counter;
number2 = number2 / 10;
}
printf("%2d digits accuracy in calculations\n", counter);
number2 = 1.0;
counter = 0;
while (1) {
result = number1 + number2;
if (result == number1)
break;
++counter;
number2 = number2 / 10.0;
}
printf("%2d digits accuracy in storage\n", counter );
return (0);
}