Когда я запускаю следующий код в VC ++ 2013 (32-разрядный, без оптимизации):
#include <cmath>
#include <iostream>
#include <limits>
double mulpow10(double const value, int const pow10)
{
static double const table[] =
{
1E+000, 1E+001, 1E+002, 1E+003, 1E+004, 1E+005, 1E+006, 1E+007,
1E+008, 1E+009, 1E+010, 1E+011, 1E+012, 1E+013, 1E+014, 1E+015,
1E+016, 1E+017, 1E+018, 1E+019,
};
return pow10 < 0 ? value / table[-pow10] : value * table[+pow10];
}
int main(void)
{
double d = 9710908999.008999;
int j_max = std::numeric_limits<double>::max_digits10;
while (j_max > 0 && (
static_cast<double>(
static_cast<unsigned long long>(
mulpow10(d, j_max))) != mulpow10(d, j_max)))
{
--j_max;
}
double x = std::floor(d * 1.0E9);
unsigned long long y1 = x;
unsigned long long y2 = std::floor(d * 1.0E9);
std::cout
<< "x == " << x << std::endl
<< "y1 == " << y1 << std::endl
<< "y2 == " << y2 << std::endl;
}
я получил
x == 9.7109089990089994e+018
y1 == 9710908999008999424
y2 == 9223372036854775808
в отладчике.
Я ошеломлен. Может кто-нибудь объяснить мне, как чертовски y1
и y2
имеют разные значения?
Обновлять:
Это происходит только в /Arch:SSE2
или /Arch:AVX
, но не в /Arch:IA32
или /Arch:SSE
.
double
, то есть 64-битное? - person user541686   schedule 31.01.2014x
, которое я вижу, является правильным, независимо от того, выполнялась ли его арифметика с 64-битной или 80-битной точностью. Поскольку это 64-битная переменная, это означает, что для ее представления было достаточно 64 бит. Это также означает, что преобразование его вunsigned long long
должно дать правильный ответ, 64 или 80 бит. Кого волнует, является лиx
64-битным или 80-битным, если оно имеет правильное значение? Как это на что-нибудь влияет? - person user541686   schedule 31.01.2014std::floor(9710908999.0089989 * 1.0E9)
. У вас есть точка зрения, что значениеy2
слишком сильно отличается, чтобы быть вызванным этим, но это нормально, если оно не точно равноy1
. - person   schedule 31.01.2014is it a codegen bug?
Я бы не стал искать другого объяснения. Ошибки с плавающей запятой обычно возникают в компиляторах Microsoft. На одной из моих работ нам пришлось перевести несколько модулей на icc из-за них. - person n. 1.8e9-where's-my-share m.   schedule 31.01.2014/Arch
. - person James Kanze   schedule 31.01.2014"%VS120COMNTOOLS%..\..\VC\bin\cl.exe" /nologo /I "%VS120COMNTOOLS%..\..\VC\include" Temp.cpp /link /LibPath:"%VS120COMNTOOLS%..\..\VC\lib" /LibPath:"%ProgramFiles(x86)%\Microsoft SDKs\Windows\v7.1A\Lib"
запускают это нормально. Вы печатаете черезstd::cout
или черезprintf
? Почему-то кажется, что printf не работает, он печатает нули для меня. - person user541686   schedule 31.01.2014static_cast<double>(static_cast<unsigned long long>(mulpow10(d, j_max))) != mulpow10(d, j_max)
в цикле, вы больше не получите этот результат, даже если он все еще используется__ftol2
! - person user541686   schedule 31.01.2014_fpreset()
до того, какy2 = std::floor(d * 1.0E9)
исправит это, я не понимаю, почему. - person user541686   schedule 31.01.2014while
оставляет значения в стеке FPU, и загрузка только что сохраненного значения позже не выполняется, потому что для этого значения больше нет места. - person   schedule 31.01.2014