Почему С++ увеличивает двойное число с более чем 6 десятичными знаками до следующего десятичного числа, фактически не изменяя значение?

Почему такое поведение происходит? что десятичное число после 6-го места увеличивается до следующего в двойном размере, но не увеличивается при преобразовании в целое число.

Это вызывает проблемы при преобразовании в int, потому что, несмотря на печать 3, d1 по-прежнему преобразуется в 2 при преобразовании в целое число, а не в 3

    double d1 = 2.999999; //6 digits after decimal
    double d2 = 2.777777;
    
    double d3 = 2.77777;  //5 digits after decimal
    double d4 = 2.99999;  
    
    cout<<d1<<endl;       //gives 3
    cout<<(int)d1<<endl;  //still gives 2 not 3
    cout<<d2<<endl;       //gives 2.777778
    
    cout<<d3<<endl;       //gives 2.77777 as expected
    cout<<d4<<endl;       //gives 2.99999 as expected

Я предполагаю, что он должен что-то делать с компиляторами или точностью, но я не уверен в этом неожиданном поведении. Пожалуйста, помогите

это не имеет ничего общего с С++. В С++ нет определенных форматов с плавающей запятой, и реализация может использовать IEEE-754 или что-то еще. Но округление при печати точно указано, а точность тоже 6 по умолчанию, поэтому очевидно печатание 2.77777 сильно отличается от 2.777777

phuclv 12.01.2023 06:42

Никакого увеличения здесь не происходит. Когда значение отображается как 3, это не означает, что значение изменилось. Это именно то, что было определено программой, как правильный способ отображения значения.

Karl Knechtel 12.01.2023 06:42

Поведение по умолчанию функции std::cout заключается в том, что она будет печатать двойные числа с точностью до 6 цифр. Это не меняет значение d1, но округляет его при отображении.

Nathan Pierson 12.01.2023 06:42

Отвечает ли это на ваш вопрос? Как с помощью cout вывести двойное значение с полной точностью?

Karl Knechtel 12.01.2023 06:44

Я думаю, что основная проблема здесь заключается в том, что когда вы печатаете число с плавающей запятой, по умолчанию оно округляется до определенного количества значащих цифр (что, кстати, не то же самое, что «цифры после запятой»). Если вы не измените его, количество значащих цифр по умолчанию равно 6. Вот почему 2,999999 (с семью значащими цифрами) было округлено, а правильно округленное значение равно 3. Однако, когда вы приводите это число к (int), это преобразование просто выдает уберите дробную часть, дав вам 2.

Steve Summit 12.01.2023 14:13

Также вы должны знать, что все эти разговоры о «значащих цифрах» или «знаках после запятой» применимы только тогда, когда мы печатаем числа в десятичном формате для чтения людьми! Внутренне числа с плавающей запятой обычно представляются в двоичном формате с основанием 2 и на самом деле вообще не содержат десятичных цифр.

Steve Summit 12.01.2023 14:14
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
6
114
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Это потому, что точность по умолчанию для cout равна 6. Компилятор достаточно точно распознает все значения, но вывод округляется до 6 знаков после запятой. Если вам нужен точный результат, вы можете изменить код следующим образом:

cout << setprecision(7);
double d1 = 2.999999; //6 digits after decimal
double d2 = 2.777777;

double d3 = 2.77777;  //5 digits after decimal
double d4 = 2.99999;  

cout<<d1<<endl;       //gives 2.999999
cout<<(int)d1<<endl;  //still gives 2 not 3
cout<<d2<<endl;       //gives 2.777777

cout<<d3<<endl;       //gives 2.77777 as expected
cout<<d4<<endl;       //gives 2.99999 as expected

Кроме того, вы не получите «точный» результат, установив точность на 7; вы получаете ожидаемый результат, но 2.777777 не может быть точно представлено в форматах с плавающей запятой IEEE, поэтому вы получаете самое близкое приближение к сохраненному значению.

Pete Becker 12.01.2023 15:54

Другие вопросы по теме