简体   繁体   English

浮点精度细微差别

[英]Floating point precision nuances

I found this code in NVIDIA's CUDA SDK samples. 我在NVIDIA的CUDA SDK示例中找到了此代码。

void computeGold( float* reference, float* idata, const unsigned int len)
{
    reference[0] = 0;
    double total_sum = 0;
    unsigned int i;
    for( i = 1; i < len; ++i)
    {
        total_sum += idata[i-1];
        reference[i] = idata[i-1] + reference[i-1];
    }
    // Here it should be okay to use != because we have integer values
    // in a range where float can be exactly represented
    if (total_sum != reference[i-1])
        printf("Warning: exceeding single-precision accuracy.  Scan will be inaccurate.\n");
}
//(C) Nvidia Corp

Can somebody please tell me a case where the warning would be printed, and most importantly, why. 有人可以告诉我一个会打印警告的情况,最重要的是,为什么。

Normally, you cannot sum many floating point numbers. 通常,您不能将许多浮点数相加。

Eventually the sum becomes different order of magnitude than every new added number, so precision is lost. 最终,总和变得与每个新添加的数字不同,因此精度会丢失。 For example, in case of float, adding a million numbers of the same order of magnitude gives the same result as ten million, because by the time it's done, every new number added doesn't change anything. 例如,在浮动的情况下,添加一百万个相同数量级的数字会产生与一千万个相同的结果,因为到它完成时,每添加一个新数字都不会改变任何东西。

There're algorithms around this which involve a couple of multiplications for every added number (indeed, just to sum numbers properly). 围绕此算法的算法涉及每增加一个数字的几次乘法(实际上,只是为了正确地对数字求和)。 Yeah, floating point is tricky. 是的,浮点很棘手。

See http://floating-point-gui.de/ http://floating-point-gui.de/

The function is written with a certain range of input data in mind. 该函数在编写时考虑了一定范围的输入数据。 If that input data expectation isn't met, the warning will print: 如果未满足输入数据期望,则将显示警告:

#include <stdio.h>
#define COUNT_OF(x) (sizeof(x)/sizeof(0[(x)]))

void computeGold( float* reference, float* idata, const unsigned int len)
{
    double total_sum = 0;
    unsigned int i;

    reference[0] = 0;

    for( i = 1; i < len; ++i)
    {
        total_sum += idata[i-1];
        reference[i] = idata[i-1] + reference[i-1];
    }
    // Here it should be okay to use != because we have integer values
    // in a range where float can be exactly represented
    if (total_sum != reference[i-1])
        printf("Warning: exceeding single-precision accuracy.  Scan will be inaccurate.\n");
}
//(C) Nvidia Corp


float data[] = {
    1.0,
    2.0,
    3.0,
    4.0,
    5.0
};

float data2[] = {
    123456.0,
    999999.0,
    999999.0,
    999999.0,
    999999.0,
    999999.0,
    999999.0,
    999999.0,
    999999.0,
    999999.0,
    999999.0,
    999999.0,
    999999.0,
    999999.0,
    999999.0,
    999999.0,
    999999.0,
    999999.0,
    123456.0
};

float ref[COUNT_OF(data2)] = {0.0};

int main()
{
    computeGold( ref, data, COUNT_OF(data));
    computeGold( ref, data2, COUNT_OF(data2));
    return 0;
}

A float normally has a range of something like +/- 1e38, but a precision of only about 5 or 6 digits. float通常具有类似+/- 1e38的范围,但精度仅为大约5或6位数。 This means, for example, that something like 12345678 can be stored, but it'll only be stored with ~6 digits of precision, so you'll get the warning. 这意味着,例如,可以存储12345678这样的东西,但它只能以~6位精度存储,因此您将收到警告。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM