(int)(33.46639 * 1000000) 回报 33466389
为什么会这样?
问题.
Microsoft Visual C++ 2005编译器,32位windows xp sp3,amd 64 x2 cpu.
码:
double a = 3015.0;
double b = 0.00025298219406977296;
//*((unsigned __int64*)(&a)) == 0x40a78e0000000000
//*((unsigned __int64*)(&b)) == 0x3f30945640000000
double f = a/b;//3015/0.00025298219406977296;
Run Code Online (Sandbox Code Playgroud)
计算结果(即"f")是11917835.000000000(((unsigned __int64)(&f))== 0x4166bb4160000000)虽然它应该是11917834.814763514(即((unsigned __int64)(&f))== 0x4166bb415a128aef).
即分数部分丢失.
不幸的是,我需要小数部分才能正确.
问题:
1)为什么会发生这种情况?
2)我该如何解决这个问题?
附加信息:
0)结果直接来自"监视"窗口(它没有打印,我没有忘记设置打印精度).我还提供了浮点变量的十六进制转储,所以我对计算结果非常肯定.
1)f = a/b的反汇编是:
fld qword ptr [a]
fdiv qword ptr [b]
fstp qword ptr [f]
Run Code Online (Sandbox Code Playgroud)
2)f = 3015/0.00025298219406977296; 得到正确的结果(f == 11917834.814763514,((unsigned __int64)(&f))== 0x4166bb415a128aef),但看起来在这种情况下,结果只是在编译时计算:
fld qword ptr [__real@4166bb415a128aef (828EA0h)]
fstp …Run Code Online (Sandbox Code Playgroud) 为了简化问题,我想说我想a / (b - c)在floats 上计算表达式.
为了确保结果是有意义的,我可以检查b和c是相等的:
float EPS = std::numeric_limits<float>::epsilon();
if ((b - c) > EPS || (c - b) > EPS)
{
return a / (b - c);
}
Run Code Online (Sandbox Code Playgroud)
但是我的测试表明,如果可能的话,不能保证有意义的结果,也不能不提供结果.
a = 1.0f;
b = 0.00000003f;
c = 0.00000002f;
Run Code Online (Sandbox Code Playgroud)
结果:不满足if条件,但表达式将生成正确的结果100000008(与浮点数的精度相同).
a = 1e33f;
b = 0.000003;
c = 0.000002;
Run Code Online (Sandbox Code Playgroud)
结果:满足if条件,但表达式不会产生有意义的结果+1.#INF00.
我发现检查结果更可靠,而不是参数:
const float INF = numeric_limits<float>::infinity();
float x = a / (b - c); …Run Code Online (Sandbox Code Playgroud) 我知道一个类似的问题,但我想请求人们对我的算法的意见,以尽可能准确地将浮点数与实际成本相加.
这是我的第一个解决方案:
put all numbers into a min-absolute-heap. // EDIT as told by comments below
pop the 2 smallest ones.
add them.
put the result back into the heap.
continue until there is only 1 number in the heap.
Run Code Online (Sandbox Code Playgroud)
这个将采用O(n*logn)而不是正常的O(n).这真的值得吗?
第二个解决方案来自我正在研究的数据的特征.这是一个巨大的正数列表,具有相似的数量级.
a[size]; // contains numbers, start at index 0
for(step = 1; step < size; step<<=1)
for(i = step-1; i+step<size; i+=2*step)
a[i+step] += a[i];
if(i < size-1)
a[size-1] += a[i];
Run Code Online (Sandbox Code Playgroud)
基本思想是以"二叉树"方式进行求和.
注意:它是伪C代码.step<<=1表示乘以步数2.这一个将取O(n).我觉得可能有更好的方法.你能推荐/批评吗?
IEEE 754浮点除法的可逆性是什么?我的意思是它是否由标准保证,如果double y = 1.0 / x那时x == 1.0 / y,即x可以一点一滴地精确恢复?
当案件y是infinity或NaN有明显的例外.
在尝试处理浮点运算问题时,我遇到了一些有点混乱的问题.
一,代码.我已经将我的问题的本质提炼到这个例子中:
#include <iostream>
#include <iomanip>
using namespace std;
typedef union {long long ll; double d;} bindouble;
int main(int argc, char** argv) {
bindouble y, z, tau, xinum, xiden;
y.d = 1.0d;
z.ll = 0x3fc5f8e2f0686eee; // double 0.17165791262311053
tau.ll = 0x3fab51c5e0bf9ef7; // double 0.053358253178712838
// xinum = double 0.16249854626123722 (0x3fc4ccc09aeb769a)
xinum.d = y.d * (z.d - tau.d) - tau.d * (z.d - 1);
// xiden = double 0.16249854626123725 (0x3fc4ccc09aeb769b)
xiden.d = z.d * (1 - tau.d);
cout << hex << …Run Code Online (Sandbox Code Playgroud) 对于1-D numpy数组,这两个表达式应该产生相同的结果(理论上):
(a*b).sum()/a.sum()
dot(a, b)/a.sum()
Run Code Online (Sandbox Code Playgroud)
后者使用dot()并且更快.但哪一个更准确?为什么?
一些背景如下.
我想用numpy计算样本的加权方差.我dot()在另一个答案中找到了这个表达式,并附有评论说它应该更准确.但是没有给出解释.
甲float(又名单个)值是一个4字节的值,并且应该代表任何实值的数.由于它的格式化方式和有限的字节数,它可以表示最小值和最大值,并且它具有有限的精度,具体取决于它自己的值.
我想知道是否有办法在浮点数的有限精度下获得高于或低于某个参考值的最接近的可能值.对于整数,这是微不足道的:只需添加或减去1.但是使用a float,您不能简单地添加或减去最小浮点值并期望它与原始值不同.即
float FindNearestSmaller (const float a)
{
return a - FLT_MIN; /* This doesn't necessarily work */
}
Run Code Online (Sandbox Code Playgroud)
事实上,上述几乎永远不会奏效.在上面的例子中,返回通常仍然相等a,因为FLT_MIN它远远超出了精度a.您可以轻松地自己尝试:它适用于例如0.0f或非常少量的订单FLT_MIN,但不适用于0到100之间的任何订单.
那么在a给定浮点精度的情况下,如何获得最接近但小于或大于的值?
注意:虽然我主要对C/C++答案感兴趣,但我认为答案适用于大多数编程语言.
我必须检查包含平方根的不等式.为了避免由于浮点不准确和舍入导致的错误结果,我使用std::nextafter()上限/下限:
#include <cfloat> // DBL_MAX
#include <cmath> // std::nextafter, std::sqrt
double x = 42.0; //just an example number
double y = std::nextafter(std::sqrt(x), DBL_MAX);
Run Code Online (Sandbox Code Playgroud)
a)y*y >= x使用GCC编译器保证吗?
b)这是否适用于其他操作+ - * /,甚至std::cos()和std::acos()?
c)是否有更好的方法来获得上限/下限?
更新:我读过这不是C++标准保证的,但应该按照IEEE-754工作.这适用于GCC编译器吗?
我是偏执狂,其中一个函数可能会给出一个不正确的结果:
std::floor(2000.0 / 1000.0) --> std::floor(1.999999999999) --> 1
or
std::ceil(18 / 3) --> std::ceil(6.000000000001) --> 7
Run Code Online (Sandbox Code Playgroud)
可以这样的事情发生吗?如果确实存在这样的风险,我打算使用以下功能以便安全地工作.但是,这真的有必要吗?
constexpr long double EPSILON = 1e-10;
intmax_t GuaranteedFloor(const long double & Number)
{
if (Number > 0)
{
return static_cast<intmax_t>(std::floor(Number) + EPSILON);
}
else
{
return static_cast<intmax_t>(std::floor(Number) - EPSILON);
}
}
intmax_t GuaranteedCeil(const long double & Number)
{
if (Number > 0)
{
return static_cast<intmax_t>(std::ceil(Number) + EPSILON);
}
else
{
return static_cast<intmax_t>(std::ceil(Number) - EPSILON);
}
}
Run Code Online (Sandbox Code Playgroud)
(注意:我假设给定的'long double'参数适合'intmax_t'返回类型.)