乘法:uint vs float

时间:2018-02-15 01:04:18

标签: c++

为什么以下两个结果不同?无论如何,以下乘法的结果应该是整数。

uint16_t test = 500.00 * 128.51;
std::cout << test << std::endl; ----> 64254

float test = 500.00 * 128.51;
std::cout << test << std::endl; ----> 64255

2 个答案:

答案 0 :(得分:5)

(从评论转发)

要完成previously linked duplicate,500.00 * 128.51实际上略小于64255(因为128.51无法在二进制FP中准确表示)。

当转换为整数类型时,将丢弃小数(值截断),因此64254.99999 ...变为64254。

OTOH,当保留为double时,保留64254.9999 ...,默认ostream::operator<<行为是在打印时在某个小数位置舍入,所以在显示它时你会看到它就像64255一样。

答案 1 :(得分:3)

  

以下乘法的结果不具有小数。

也许它不是基数10(十进制),但是计算机不能在基数10中工作。它们在基数2中工作,而在基数2中,128.51具有更多小数小数位数可以存储在float(或实际上,任何类似的格式 - 它需要无限的位置,就像尝试写出十进制的1/3一样)。

此错误贯穿始终,尽管数学64255是一个整数,但乘法的结果更接近于64254.9999999999927240。

默认情况下,

std::cout会自动将其舍入(因为它知道发生了这种事情);但是,在转换为uint16_t期间,会发生愚蠢的截断,导致错误的64254。

使用一些I / O操纵器魔术,我们可以更清楚地看到这一点:

#include <iostream>
#include <iomanip>

int main()
{
    std::cout << std::fixed << std::setprecision(16) << (500.00 * 128.51) << std::endl;
    std::cout << uint16_t(500.00 * 128.51) << std::endl;
}

// 64254.9999999999927240
// 64254

live demo