Почему в C++ для double в числе только 5 цифр после запятой
В языке C++ при определении переменных необходимо указать их тип, причём в дальнейшем тип менять нельзя.
Для числовых переменных распространёнными типами являются int, short, long, float и double.
К примеру, переменная с типом данных float — это число с плавающей точкой, для хранения которого используется 4 байта, а это 6-9 значимых цифр, обычно 7.
А переменная с типом данных double — это число с плавающей точкой, для хранения которого используется 8 байт, а это примерно 15-18 значимых цифр, обычно 16.
Зная это, рассмотрим следующий простейший код — для его выполнения, сохраните код в файл test.cpp:
Теперь скомпилируйте его:
Результат выполнения очень необычен:
Число 230.4732 обрезано до 230.473 — потерян одна цифра после запятой. А в числе типа double, значение которого 30949.12345678, обрезалось до 30949.1 — то есть вместо предполагаемых 15-18 значимых цифр получено только 6…
Отсюда возникает вопрос, почему в числе типа double можно использовать только 6 значимых цифр?
На самом деле, число double d содержит все цифры после запятой, которые присвоены этой переменной — всё дело в том, как выполняется проверка числа. У метода cout имеются свои настройки по умолчанию для вывода и форматирования чисел — если в числе больше 6 разрядов, то обрезаются цифры после запятой, если до запятой также больше 6 цифр, то используется научная запись числа, например 1.23457e+14.
Такое поведение по умолчанию cout можно исправить. Для этого, во-первых, необходимо добавить новый заголовок #include <iomanip>.
Во-вторых нужно использовать std::setprecision(n), где n — это новая величина точности.
При использовании в выражении out << setprecision(n) или in >> setprecision(n) устанавливает для параметра точности потока out или in значение ровное n.
Отредактирует код нашей программы:
Заново скомпилируем и выполним его. Результат:
Именно этот результат мы и ожидали:
Отметим ещё раз — в самой программе используются все возможные знаки и разряды чисел, цифры обрезались в момент вывода.
как повысить точность без поплавков C
Как я могу сделать это точнее без использования float с или double s, и, самое главное, не увеличивайте слишком сильно размер моего кода.
С уважением, Sonite
Поскольку у меня есть uint24_t, я думаю, что просто увеличу ManualFlow * 10 до Manualflow * 100. Это сделает его более точным. Самые большие значения, которые я могу иметь: «1000» * 10/6 * «100» / 100 * 414 = 689724 — Christian
Вы там тратите биты . Если у вас есть uint8_t и uint24_t, это означает, что вы можете сдвинуть uint8_t влево на 16 бит. Это примерно в 600 раз точнее, чем умножение на 100, и, опять же, намного быстрее, умножение очень дорогое по сравнению с битовым сдвигом. — Ștefan
6 ответы
Вы можете посмотреть на арифметику с фиксированной запятой:
И технический отчет 18037 от WG14 (последняя версия ISO / IEC TR 18037: 2008, к сожалению, не бесплатна):
ответ дан 02 апр.
Если вы уверены, что результат никогда не переполнится, делайте все умножение перед делениями:
Если вам нужна более чем целочисленная точность, но вы хотите избежать использования чисел с плавающей запятой, рассмотрите возможность использования арифметика с фиксированной запятой .
ответ дан 02 апр.
Ах . это близкое. Наибольшее значение, которое я мог бы здесь иметь, будет: 400 * (100) * 414 / (6 * 14) = 16560000. Как вы говорите, нужно быть уверенным, что оно не переполнится. Я думаю, что пойду еще раз. — Кристиан
Вы имеете в виду арифметику с фиксированной точкой (в отличие от арифметики с плавающей точкой). Вы всегда можете увеличить размер ваших целых чисел до чего-то вроде uint64_t и умножить более чем на 10 для достижения желаемой точности.
Однако я бы рекомендовал использовать фиксированную точку base-2 (т.е. сдвиг влево на определенное количество битов, а не умножение на 10 до определенной степени). Это (намного) быстрее и может быть точнее.
ответ дан 02 апр.
Умножьте все ваши входные данные, например, на (1 << 8) на более крупные типы данных, затем выполните необходимые математические вычисления, затем разделите ответ на (1 << 8).
ответ дан 02 апр.
Мой исходный код имел не очень хорошую точность и был «таким большим».
Сделав это ниже, я увеличил код до «38 байт» и добился большей точности.
Наилучшая точность, которую я получил при использовании фиксированной точки, но она увеличила код до намного «1148 байт ->
Надеюсь, это поможет кому-нибудь другому!
С уважением, Sonite
ответ дан 03 апр.
Возможно, я немного опоздал с ответом за исходный плакат, но для потомков следует также отметить, что деления с фиксированной точкой часто также можно избежать, когда скорость действительно критична для небольшого процессора. Деление с помощью переменных часто неизбежно, но можно (почти) всегда использовать умножение и сдвиг вместо деления на константу, что может съесть много циклов процессора, особенно для типов, больших, чем ширина данных небольшого процессора. Вместо
Вы можете использовать:
Примечание: это менее читаемый код, но если это алгоритм, где производительность критична, эту оптимизацию можно использовать (с осторожностью).
ответ дан 04 мая ’12, 04:05
Не тот ответ, который вы ищете? Просмотрите другие вопросы с метками c int microchip or задайте свой вопрос.
Вычисления с повышенной точностью в C#
Классическая ошибка перемножения яблок на груши. Внимательно посмотрите, какими типами орудуете.
если так, то все работает
Кстати, вместо Math.Cos((double)5*x), правильнее написать Math.Cos(5.00d*x)
Но становится бессмысленным использование типа decimal.
Вот так всегда, моя невнимательность меня губит:)
Не прочел первую часть вопроса.
В любом случае, стандартную функцию Math.Cos напрямую для типа decimal использовать не получится.
При конвертации всеравно точность потеряется.
А вообще, я тут почитал это
И получил нечто похожее на то, что нужно автору
using System;
using System.Globalization;
namespace Test
<
class Program
<
static void Main(string[] args)
<
double i = 1, j = 3d;
Console.WriteLine(f(i, j).ToString(«E50», CultureInfo.InvariantCulture));
Console.Write(«\nPress any key to exit»);
Console.ReadKey();
>
static double f(double x, double y)
<
double fx;
fx = 10d * Math.Cos(5d * x) — 2d * y;
return fx;
>
>
>
C# не предполагает высокоточных вычислений. И вообще машинная погрешность в операциях * / ^ над числами с плавающей точкой дает такую погрешность, что смысла расширять точность double еще на несколько цифр просто нет.
А decimal внутри состоит из 2х int64 )))
Хотите высокую точность — используйте либо лучше всего — символьные пакеты, либо как минимум — дробный тип данных )))
Как увеличить точность double C++?
Пытаюсь сделать одинаковое вычисление с помощью C++ чтобы точность была как в языке Ruby, однако C++ жестче округляет значения а делать round() для каждого прохода не вариант так как чисел после запятой может быть от 1 до 16, что посоветуете?
- Вопрос задан более трёх лет назад
- 4989 просмотров
- Вконтакте

Не совсем корректно поставлен вопрос, тем что тебе нужно — ты понижаешь точность.
У float 23 мантисы, у double 52. Теоритически дабл имеет двухкратную точность в сравнении с float.
Это как понимать?
У тебя может быть до 16 чисел после запятой — это уже сильно округленно. Поставь себе конкретно вопрос — сколько именно чисел после запятой ты хочешь видеть в итоге? На столько и округляй.
Если же отвечать конкретно на формулировку твоего вопроса, а именно «как повысить точность», то 1 из ответов был бы long double