Все целочисленные значения идеально представлены в виде двойников? [дубликат]
этот вопрос уже есть ответ здесь:
представление целых чисел в двойниках
5 ответов
мой вопрос заключается в том, что все целочисленные значения гарантированно имеют идеальное двойное представление.
рассмотрим следующий пример кода, который печатает "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?
Я пробовал некоторые другие цифры и это всегда было правдой, но не смог найти ничего о том, является ли это случайным или преднамеренным.
Примечание: это отличается от этот вопрос (помимо языка) так как я добавляю два целые.
5 ответов:
отказ от ответственности (как предложил Тоби Спейт): хотя представления 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 бита можно представить всеintS как double, но для 64-битных целых чисел, конечно, это уже не так. Чтобы быть более точным (как отметил LThode в комментарии): IEEE 754 двойная точность может гарантировать это до 53 бит (52 бита significand + неявное ведущее 1 бит.)ответ: да для 32-битных входов, нет для 64-битных входов.
(это верно для серверных/настольных сред ЦП общего назначения, но другие архитектуры могут вести себя по-другому.)
Практический Ответ как говорит Малкольм Маклин: 64-битные двойники являются адекватным целочисленным типом почти для всех целых чисел, которые, вероятно, будут считать вещи в реальной жизни.
для эмпирически склонных, попробуйте этой:
#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; }время успеха: 0.85 память: 15240 сигнал: 0
Subquestion: Что касается вопроса о дробных различиях. Возможно ли иметь целое число, которое преобразуется в двойник, который просто отклоняется от правильного значения на долю, но который преобразуется обратно в то же целое число из-за округления?
ответ-нет, потому что любое целое число, которое преобразуется туда и обратно в одно и то же значение, на самом деле представляет собой то же целое значение в double. Для меня самое простое объяснение (предложенное ilkkachu) для этого заключается в том, что с помощью экспоненты
2^exponentширина ступени должна быть в два. Таким образом, за самым большим 52(+1 знак) битовым целым числом никогда не бывает двух двойных значений с расстоянием меньше 2, что решает проблему округления.
нет. Предположим, что у вас есть 64-разрядный целочисленный тип и 64-разрядный тип с плавающей запятой (что типично для A
double). Существует 2^64 возможных значения для этого целочисленного типа и 2^64 возможных значения для этого типа с плавающей запятой. Но некоторые из этих значений с плавающей запятой (фактически, большинство из них) не представляют целочисленных значений, поэтому тип с плавающей запятой может представлять меньше целочисленных значений, чем целочисленный тип.
ответа нет. Это работает только если
ints-32 бит, что, хотя и верно на большинстве платформ, не гарантируется стандартом.два целых числа могут иметь одинаковое двойное представление.
например, этой
#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 и (n-1) имеют одно и то же двойное представление
т. е. оба 2397083434877565865 и 2397083434877565864 преобразуются в то же самое
double.обратите внимание, что я использовал
int64_tздесь, чтобы гарантировать 64-разрядные целые числа, которые-в зависимости от вашей платформы - также может быть чтоintесть.
у вас есть 2 разных вопроса:
все целочисленные значения идеально представлены в виде двойников?
на это уже ответили другие люди (TL; DR: это зависит от точности
intиdouble).рассмотрим следующий пример кода, который печатает "Same": [...] Гарантируется ли это для любой архитектуры, любого компилятора, любых значений a и b?
ваш код добавляет два
ints и затем преобразует результат в double. Суммаints будет переполнение для определенных значений, но сумма двух отдельно-преобразованоdoubleне будет (как правило). Для этих значений результаты будут отличаться.
короткий ответ: "возможно". Портативный ответ- "не везде".
это действительно зависит от вашей платформы, и в частности, о
- размер и представление
double- ассортимент
intдля платформ, использующих IEEE-754 удваивается, это мая быть true, если
int53-бит или меньше. Для платформ гдеintбольше, чемdouble, Это явно ложь.вы возможно, потребуется изучить свойства на вашем хосте времени выполнения, используя
std::numeric_limitsиstd::nextafter.

Comments