【发布时间】:2017-05-31 14:25:13
【问题描述】:
我目前正在编写一个模板化的帮助方法,它可以将 C 数字(包括 unsigned long long)转换为 GMP 库中的 mpz_class 数字。在这期间,有一个电话到std::abs。
然而,事实证明,对于 C++17 (g++ 6.3.1),
#include <iostream>
#include <cmath>
int main()
{
std::cout << (unsigned long long)std::abs(9484282305798401ull);
}
给出9484282305798400 的错误输出。
据我从cmath 了解到,std::abs 首先将参数转换为双精度值。
根据 C++ 文档,double 有 52 个尾数位,这意味着在精度损失之前,我必须严格小于 2^52 = 4503599627370496 的最大整数值。
我是否正确地说,由于 9484282305798401 超过了这个限制,std::abs 最终会丢弃精度以给出不正确的答案?
为了澄清,我绝对知道要求无符号整数的绝对值是完全没有意义的。但是,我希望模板化函数适用于一般 C 数字,而不必分别为每个有符号和无符号类型专门创建一个特化。
【问题讨论】:
-
如果可以,在无符号类型上调用
abs有什么意义? -
我正在编写一个模板函数,该函数在调用 GMP 库的 mpz_import 类之前会经过一些算术运算;在这之间,可能需要对有符号数字的 std::abs 进行调用。
-
请注意,虽然 IEEE 754 双精度确实使用 52 位来存储尾数,但实际上有 53 位,因为该值已标准化并且存在“隐式 1”(请参阅此 SO 帖子:@987654323 @)
标签: c++ c++11 floating-point precision c++17