Откуда берется шум в ToString("G51")?

Если вы оцениваете

(Math.PI).ToString("G51")

результат

"3,141592653589793115997963468544185161590576171875"

Math.Pi правильно до 15-го знака после запятой, что соответствует точности double. «G17» используется для кругового обхода, поэтому я ожидал, что ToString остановится после «G17», но вместо этого он продолжал выдавать числа до «G51».

В. Поскольку цифры после 15-го десятичного знака выходят за пределы точности, обеспечиваемой 53 битами мантиссы, как вычисляются остальные цифры?

См. 0.30000000000000004.com

Richard 04.11.2022 11:54

Пожалуйста, запишите результат 1/3 в базе 10. Подсказка: вы не можете. Вы можете записывать только комбинации степеней 10 (например, 10 ^ -1 (он же 0,1), 2 * 10 ^ -1 (0,2), 10 ^ -2 (0,01) и т. д. Таким образом, 0,23 возможно, но 1/3 нет. 't 0,333, и даже не 0,334, по крайней мере, не точно Точно так же с двоичным вы можете использовать только комбинации степеней 2.

ProgrammingLlama 04.11.2022 13:10

@ProgrammingLlama, @Richard Это не моя точка зрения. Двойная мантисса имеет 53 бита, что соответствует 15 десятичным знакам. Так откуда же берется шум после 17-го знака после запятой? ToString("G51") их выдумывает?

participant 04.11.2022 14:10

Я проголосовал за открытие. В предложенном дубликате есть много ответов, но я не думаю, что какой-либо из них напрямую касается этого вопроса. Обратите внимание, что десятичные цифры кажутся просто точным значением с основанием 10 приблизительного двойного числа.

President James K. Polk 04.11.2022 22:11
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
65
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Метод .ToString("G51") использует «школьную математику». Сначала он берет целую часть, затем умножает Remainder на 10, использует целую часть этого вычисления и умножает Remainder часть на 10.

Это будет продолжаться до тех пор, пока есть остаток и до 51 десятичных цифр.

Поскольку у double есть показатель степени, он будет иметь остаток примерно с 18 десятичными цифрами, что дает следующую цифру в методе ToString.

Однако, как вы видели, часть Remainder не является точной, а просто результатом математической функции.

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

Двойник имеет 53-битную мантисса, которая соответствует 15 десятичным знакам.

Двойник имеет 53-битную мантисса, которая соответствует примерно 15 десятичным знакам.

Math.Pi усекается до 53 бит в двоичном формате, что не совсем равно

3.1415926535897

но это также не совсем равно

3.14159265358979

, так далее.

Точно так же, как 1/3 — это не совсем 0,3 или 0,33 и т. д.

Если вы продолжите десятичное расширение достаточно долго, оно в конечном итоге прекратится или начнет повторяться, поскольку Math.PI, в отличие от π, является рациональным числом.

И как вы можете убедиться с типом BigRational

using System.Numerics;

var r = new BigRational(Math.PI);
BigRational dem;

BigRational.NumDen(r, out dem);
var num = r * dem;

Console.WriteLine(num);
Console.WriteLine("-----------------");
Console.WriteLine(dem);

это

884279719003555
---------------
281474976710656

И поскольку знаменатель является степенью числа 2 (что должно быть, поскольку Math.PI имеет двоичную мантисса и, следовательно, завершающее представление в базе 2). Следовательно, он также имеет завершающее представление в базе 10, что и было дано (Math.PI).ToString("G51"):

3.141592653589793115997963468544185161590576171875

в качестве

Console.WriteLine(r == BigRational.Parse("3.141592653589793115997963468544185161590576171875"));

выходы

True

точное значение 884279719003555/281474976710656 равно 3,141592653589793115997963468544185161590576171875

phuclv 05.11.2022 15:22

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

Как подсчитать общее количество цифр в байте [], если вы суммируете массив
Почему результат Math.pow() и * отличается при вычислении ответов в java? и как java вычисляет математику в оперативной памяти?
Unity вычисляет, сколько объектов перемещается по заданной оси
Программа, которая считывает ряд строк, каждая из которых содержит положительные целые числа, и выводит сумму первой строки с четным числом целых чисел, оканчивающихся на 3
Сегменты линии пересекаются с общими начальной и конечной точками
Программа Python, отображающая высоту брошенного мяча. Программа ничего не выводит
Почему мой код дает ошибку, имя «sin» не определено?
Функция, которая получает целое число n>0 и сообщает, образуют ли его цифры (по основанию 10) неубывающую последовательность (каждая цифра >= предыдущей)
Как распределить элементы «n» в массиве размера «M», чтобы элементы распределялись равномерно?
Метод, который разбивает 2D-массив на 4 части в Java