所有整数值都完美地表示为双精度值吗?
Are all integer values perfectly represented as doubles?
我的问题是是否保证所有整数值都具有完美的双精度表示。
考虑以下打印 "Same" 的代码示例:
// Example program
#include <iostream>
#include <string>
int main()
{
int a = 3;
int b = 4;
double d_a(a);
double d_b(b);
double int_sum = a + b;
double d_sum = d_a + d_b;
if (double(int_sum) == d_sum)
{
std::cout << "Same" << std::endl;
}
}
这是否保证对任何体系结构、任何编译器、a
和 b
的任何值都是正确的?将任何整数 i
转换为 double
,总是表示为 i.0000000000000
而不是,例如 i.000000000001
?
我尝试了一些其他数字,它总是正确的,但无法找到关于这是巧合还是设计的任何信息。
注意:这不同于 this question(语言除外),因为我将两个整数相加。
答案是否定的。这仅在 int
是 32 位的情况下有效,虽然在大多数平台上都是如此,但标准并不能保证。
两个整数可以共享相同的双精度表示。
例如,this
#include <iostream>
int main() {
int64_t n = 2397083434877565865;
if (static_cast<double>(n) == static_cast<double>(n - 1)) {
std::cout << "n and (n-1) share the same double representation\n";
}
}
将打印
n and (n-1) share the same double representation
即2397083434877565865 和 2397083434877565864 都将转换为相同的 double
.
请注意,我在这里使用 int64_t
来保证 64 位整数,这取决于您的平台 - 也可能是 int
。
免责声明(如 Toby Speight 所建议):虽然 IEEE 754 表示非常普遍,但允许实现使用满足语言要求的任何其他表示。
双精度数以mantissa * 2^exponent
的形式表示,即一些位用于双精度数的非整数部分。
bits range precision
float 32 1.5E-45 .. 3.4E38 7- 8 digits
double 64 5.0E-324 .. 1.7E308 15-16 digits
long double 80 1.9E-4951 .. 1.1E4932 19-20 digits
分数中的部分也可以用指数来表示整数,指数去掉点后的所有数字。
例如2,9979 · 10^4 = 29979。
因为一个普通的 int
通常是 32 位的,你可以将所有的 int
表示为双精度,但是对于 64 位整数当然这不再是真的。更准确地说(正如 LThode 在评论中指出的那样):IEEE 754 双精度最多可以保证 53 位(有效数的 52 位 + 隐式前导 1 位)。
答案:32 位整数是,64 位整数不是。
(这对于 server/desktop 通用 CPU 环境是正确的,但其他体系结构的行为可能不同。)
实用答案 正如 Malcom McLean 所说:对于几乎所有可能在现实生活中计数的整数,64 位双精度整数类型都是合适的。
对于经验倾向的人,请尝试 this:
#include <iostream>
#include <limits>
using namespace std;
int main() {
double test;
volatile int test_int;
for(int i=0; i< std::numeric_limits<int>::max(); i++) {
test = i;
test_int = test;
// compare int with int:
if (test_int != i)
std::cout<<"found integer i="<<i<<", test="<<test<<std::endl;
}
return 0;
}
Success time: 0.85 memory: 15240 signal:0
子问题:
关于分数差异的问题。是否有可能将一个整数转换为 double,它与正确的值相差一个分数,但由于四舍五入而转换回相同的整数?
答案是否定的,因为任何整数来回转换为相同的值,实际上在double中表示相同的整数值。对我来说,最简单的解释(由 ilkkachu 建议)是使用指数 2^exponent
步长必须始终是 2 的幂。因此,除了最大的52(+1符号)位整数之外,绝不会出现距离小于2的两个double值,这就解决了舍入问题。
没有。假设您有一个 64 位整数类型和一个 64 位浮点类型(这是典型的 double
)。该整数类型有 2^64 个可能值,该浮点类型有 2^64 个可能值。但是其中一些浮点值(实际上是大多数)并不表示整数值,因此浮点类型可以表示的整数值少于整数类型。
简短的回答是 "possibly"。便携式答案是 "not everywhere".
这真的取决于您的平台,尤其是
double
的大小和表示
- 范围
int
对于使用 IEEE-754 双精度的平台,如果 int
为 53 位或更小,则 可能 为真。对于int
大于double
的平台,显然是假的
您可能希望能够使用 std::numeric_limits
和 std::nextafter
来调查运行时主机上的属性。
您有 2 个不同的问题:
Are all integer values perfectly represented as doubles?
其他人已经回答了(TL;DR:这取决于 int
和 double
的精度)。
Consider the following code sample that prints "Same": [...] Is this guaranteed to be true for any architecture, any compiler, any values of a and b?
您的代码添加两个 int
,然后 然后 将结果转换为双精度。 int
的总和 将 溢出某些值,但两个单独转换的 double
的总和不会(通常)。对于这些值,结果会有所不同。
我的问题是是否保证所有整数值都具有完美的双精度表示。
考虑以下打印 "Same" 的代码示例:
// Example program
#include <iostream>
#include <string>
int main()
{
int a = 3;
int b = 4;
double d_a(a);
double d_b(b);
double int_sum = a + b;
double d_sum = d_a + d_b;
if (double(int_sum) == d_sum)
{
std::cout << "Same" << std::endl;
}
}
这是否保证对任何体系结构、任何编译器、a
和 b
的任何值都是正确的?将任何整数 i
转换为 double
,总是表示为 i.0000000000000
而不是,例如 i.000000000001
?
我尝试了一些其他数字,它总是正确的,但无法找到关于这是巧合还是设计的任何信息。
注意:这不同于 this question(语言除外),因为我将两个整数相加。
答案是否定的。这仅在 int
是 32 位的情况下有效,虽然在大多数平台上都是如此,但标准并不能保证。
两个整数可以共享相同的双精度表示。
例如,this
#include <iostream>
int main() {
int64_t n = 2397083434877565865;
if (static_cast<double>(n) == static_cast<double>(n - 1)) {
std::cout << "n and (n-1) share the same double representation\n";
}
}
将打印
n and (n-1) share the same double representation
即2397083434877565865 和 2397083434877565864 都将转换为相同的 double
.
请注意,我在这里使用 int64_t
来保证 64 位整数,这取决于您的平台 - 也可能是 int
。
免责声明(如 Toby Speight 所建议):虽然 IEEE 754 表示非常普遍,但允许实现使用满足语言要求的任何其他表示。
双精度数以mantissa * 2^exponent
的形式表示,即一些位用于双精度数的非整数部分。
bits range precision
float 32 1.5E-45 .. 3.4E38 7- 8 digits
double 64 5.0E-324 .. 1.7E308 15-16 digits
long double 80 1.9E-4951 .. 1.1E4932 19-20 digits
分数中的部分也可以用指数来表示整数,指数去掉点后的所有数字。
例如2,9979 · 10^4 = 29979。
因为一个普通的 int
通常是 32 位的,你可以将所有的 int
表示为双精度,但是对于 64 位整数当然这不再是真的。更准确地说(正如 LThode 在评论中指出的那样):IEEE 754 双精度最多可以保证 53 位(有效数的 52 位 + 隐式前导 1 位)。
答案:32 位整数是,64 位整数不是。
(这对于 server/desktop 通用 CPU 环境是正确的,但其他体系结构的行为可能不同。)
实用答案 正如 Malcom McLean 所说:对于几乎所有可能在现实生活中计数的整数,64 位双精度整数类型都是合适的。
对于经验倾向的人,请尝试 this:
#include <iostream>
#include <limits>
using namespace std;
int main() {
double test;
volatile int test_int;
for(int i=0; i< std::numeric_limits<int>::max(); i++) {
test = i;
test_int = test;
// compare int with int:
if (test_int != i)
std::cout<<"found integer i="<<i<<", test="<<test<<std::endl;
}
return 0;
}
Success time: 0.85 memory: 15240 signal:0
子问题: 关于分数差异的问题。是否有可能将一个整数转换为 double,它与正确的值相差一个分数,但由于四舍五入而转换回相同的整数?
答案是否定的,因为任何整数来回转换为相同的值,实际上在double中表示相同的整数值。对我来说,最简单的解释(由 ilkkachu 建议)是使用指数 2^exponent
步长必须始终是 2 的幂。因此,除了最大的52(+1符号)位整数之外,绝不会出现距离小于2的两个double值,这就解决了舍入问题。
没有。假设您有一个 64 位整数类型和一个 64 位浮点类型(这是典型的 double
)。该整数类型有 2^64 个可能值,该浮点类型有 2^64 个可能值。但是其中一些浮点值(实际上是大多数)并不表示整数值,因此浮点类型可以表示的整数值少于整数类型。
简短的回答是 "possibly"。便携式答案是 "not everywhere".
这真的取决于您的平台,尤其是
double
的大小和表示
- 范围
int
对于使用 IEEE-754 双精度的平台,如果 int
为 53 位或更小,则 可能 为真。对于int
大于double
的平台,显然是假的
您可能希望能够使用 std::numeric_limits
和 std::nextafter
来调查运行时主机上的属性。
您有 2 个不同的问题:
Are all integer values perfectly represented as doubles?
其他人已经回答了(TL;DR:这取决于 int
和 double
的精度)。
Consider the following code sample that prints "Same": [...] Is this guaranteed to be true for any architecture, any compiler, any values of a and b?
您的代码添加两个 int
,然后 然后 将结果转换为双精度。 int
的总和 将 溢出某些值,但两个单独转换的 double
的总和不会(通常)。对于这些值,结果会有所不同。