Сохраняйте точность с двойным в Java

Объект people - это не список, а словарь, который вы не можете перебрать в словаре, подобном этому. Это должно сработать.

my_url = 'www.domain.com'
my_data = json.loads(requests.get(my_url).text)
for id , person in my_data['people'].items():
    print(person['info']['name'])
134
задан Makoto 28 October 2015 в 22:54
поделиться

17 ответов

Как другие упомянули, Вы, вероятно, захотите использовать BigDecimal класс, если Вы хотите иметь точное представление 11,4.

Теперь, немного объяснения в то, почему это происходит:

float и double типы примитивов в Java являются числами с плавающей точкой, где число хранится как двоичное представление части и экспоненты.

Строго говоря, значение с плавающей точкой двойной точности такой как double тип является 64-разрядным значением, где:

  • 1 бит обозначает знак (положительный или отрицательный).
  • 11 битов для экспоненты.
  • 52 бита для значащих цифр (дробная часть как двоичный файл).

Эти части объединены для создания a double представление значения.

(Источник: Википедия: Двойная точность)

Для подробного описания того, как значения с плавающей точкой обрабатываются в Java, посмотрите Раздел 4.2.3: Типы с плавающей точкой, Форматы и Значения Спецификации языка Java.

byte, char, int, long типы являются числами фиксированной точки, которые являются точным representions чисел. В отличие от чисел фиксированной точки, числа с плавающей точкой будут несколько раз (безопасный принять "большую часть времени") не смочь возвратить точное представление числа. Это - причина, почему Вы заканчиваете с 11.399999999999 как результат 5.6 + 5.8.

При требовании значения, которое точно, такой как 1,5 или 150.1005, Вы захотите использовать один из типов фиксированной точки, которые смогут представить число точно.

Как несколько раз уже был упомянут, Java имеет a BigDecimal класс, который обработает очень большие количества и очень небольшие числа.

От Java ссылка API для BigDecimal класс:

Неизменная, произвольная точность подписала десятичные числа. BigDecimal состоит из целого числа произвольной точности немасштабированное значение и 32-разрядный целочисленный масштаб. Если нуль или положительный, масштаб является количеством цифр направо от десятичной точки. Если отрицательный, немасштабированное значение числа умножается на десять к питанию отрицания масштаба. Значение числа, представленного BigDecimal, поэтому (unscaledValue × 10^-scale).

Было много вопросов на Переполнении стека, касающемся вопроса чисел с плавающей точкой и его точности. Вот список связанных вопросов, которые могут представлять интерес:

Если Вы действительно хотите перейти к вшивым песчаным деталям чисел с плавающей точкой, смотреть на то, Что Каждый Программист Должен Знать Об Арифметике С плавающей точкой.

139
ответ дан 23 November 2019 в 23:54
поделиться

Используйте BigDecimal. Это даже позволяет Вам указать округление правил (как ROUND_HALF_EVEN, который минимизирует статистическую ошибку путем округления ровному соседу, если оба будут тем же расстоянием; т.е. и 1,5 и 2,5 раунда к 2).

1
ответ дан 23 November 2019 в 23:54
поделиться

Удваивается приближения десятичных чисел в Вашем источнике Java. Вы видите последствие несоответствия между двойным (который является двоично кодированным значением), и Ваш источник (который кодируется десятичным числом).

Создание Java самое близкое двоичное приближение. Можно использовать java.text. DecimalFormat для отображения лучше выглядящего десятичного значения.

1
ответ дан 23 November 2019 в 23:54
поделиться

Умножьте все на 100 и сохраните его в длинном как центы.

2
ответ дан 23 November 2019 в 23:54
поделиться

Как другие отметили, не, все десятичные значения могут быть представлены как двоичный файл, так как десятичное число основано на полномочиях 10, и двоичный файл основан на полномочиях два.

Если точность имеет значение, используйте BigDecimal, но если Вы просто хотите дружественный вывод:

System.out.printf("%.2f\n", total);

Даст Вам:

11.40
5
ответ дан 23 November 2019 в 23:54
поделиться

Вполне уверенный Вы, возможно, превратили это в три примера строки.:)

Если Вы хотите точную точность, используйте BigDecimal. Иначе можно использовать ints, умноженный на 10 ^ безотносительно точности, которую Вы хотите.

5
ответ дан 23 November 2019 в 23:54
поделиться

Заметьте, что у Вас была бы та же проблема, если бы Вы использовали десятичную систему счисления ограниченной точности и хотели иметь дело с 1/3: 0.333333333 * 3 0.999999999, не 1.00000000.

К сожалению, 5.6, 5.8 и 11.4 просто не круглые числа в двоичном файле, потому что они включают пятые. Таким образом, представление плавающее их не точно, так же, как 0.3333 не точно 1/3.

Если все числа, которые Вы используете, являются непериодическими десятичными числами, и Вы хотите точные результаты, используете BigDecimal. Или поскольку другие сказали, если Ваши значения похожи на деньги в том смысле, что они - все несколько из 0,01, или 0.001, или что-то, затем умножают все на фиксированное питание 10 и используют интервал или долго (дополнение, и вычитание тривиальны: не упустите умножение).

Однако, если Вы довольны двоичным файлом для вычисления, но Вы просто хотите распечатать вещи в немного более дружественном формате, попробовать java.util.Formatter или String.format. В строке формата указывают точность меньше, чем полная точность двойного. К 10 значащим цифрам, скажем, 11.399999999999 11.4, таким образом, результат будет почти как точный и более человекочитаемый в случаях, где двоичный результат очень близко к значению, требующему только нескольких десятичных разрядов.

Точность для определения зависит немного от того, сколько математики Вы сделали со своими числами - в целом, чем больше Вы делаете, тем больше ошибки накопится, но некоторые алгоритмы накапливают ее намного быстрее, чем другие (их называют "нестабильными" в противоположность "стабильному" относительно погрешностей округления). Если бы все, что Вы делаете, добавляет несколько значений, то я предположил бы, что отбрасывание всего одного десятичного разряда точности уладит вещи. Эксперимент.

15
ответ дан 23 November 2019 в 23:54
поделиться

Вы сталкиваетесь с ограничением точности типа double.

Java.Math имеет некоторые арифметические средства произвольной точности.

5
ответ дан 23 November 2019 в 23:54
поделиться

Когда вы вводите двойное число, например 33.33333333333333 , вы получаете значение, которое на самом деле является ближайшим представимым значением двойной точности, а именно:

33.3333333333333285963817615993320941925048828125

Деление этого на 100 дает:

0.333333333333333285963817615993320941925048828125

, который также не может быть представлен в виде числа с двойной точностью, поэтому оно снова округляется до ближайшего представимого значения, которое является точным:

0.3333333333333332593184650249895639717578887939453125

Когда вы распечатываете это значение, оно снова округляется до 17 десятичных цифр, что дает:

0.33333333333333326
102
ответ дан 23 November 2019 в 23:54
поделиться

Вы не можете, потому что 7.3 не имеет конечного представления в двоичном формате. Ближайшее, что вы можете получить, - это 2054767329987789/2 ** 48 = 7,3 + 1/1407374883553280.

Дополнительное объяснение можно найти на http://docs.python.org/tutorial/floatingpoint.html . (Это на веб-сайте Python, но у Java и C ++ одна и та же «проблема».)

Решение зависит от того, в чем именно заключается ваша проблема:

  • Если вам просто не нравится видеть все эти шумные цифры, затем исправьте форматирование строки. Не отображайте более 15 значащих цифр (или 7 для чисел с плавающей запятой).
  • Если неточность ваших чисел нарушает такие вещи, как "if", тогда вы должны написать if (abs (x - 7.3)
  • Если вы работаете с деньгами, то, вероятно, вам действительно нужна фиксированная десятичная точка. Храните целое число центов или любую другую наименьшую единицу вашей валюты.
  • (ОЧЕНЬ ВЕРОЯТНО) Если вам нужно более 53 значащих битов (15-16 значащих цифр) точности, используйте высокоточный тип с плавающей запятой, например BigDecimal.
5
ответ дан 23 November 2019 в 23:54
поделиться

Используйте java.math.BigDecimal

Двойные числа внутренне являются двоичными дробями, поэтому они иногда не могут представлять десятичные дроби с точностью до десятичной.

3
ответ дан 23 November 2019 в 23:54
поделиться

Обратите внимание на BigDecimal, он решает проблемы, связанные с арифметикой с плавающей запятой, подобной этой.

Новый вызов будет выглядеть так:

term[number].coefficient.add(co);

Используйте setScale (), чтобы установить количество используемых десятичных знаков точности.

0
ответ дан 23 November 2019 в 23:54
поделиться

Вы можете рассмотреть возможность использования класса java.math.BigDecimal, если вам действительно нужна точная математика. Вот хорошая статья от Oracle/Sun о преимуществах BigDecimal. Хотя вы никогда не сможете представить 1/3, как кто-то упомянул, вы можете решить, насколько точным вы хотите видеть результат. setScale() - ваш друг... :)

Хорошо, поскольку у меня сейчас слишком много свободного времени, вот пример кода, который относится к вашему вопросу:

import java.math.BigDecimal;
/**
 * Created by a wonderful programmer known as:
 * Vincent Stoessel
 * xaymaca@gmail.com
 * on Mar 17, 2010 at  11:05:16 PM
 */
public class BigUp {

    public static void main(String[] args) {
        BigDecimal first, second, result ;
        first = new BigDecimal("33.33333333333333")  ;
        second = new BigDecimal("100") ;
        result = first.divide(second);
        System.out.println("result is " + result);
       //will print : result is 0.3333333333333333


    }
}

и чтобы подключить мой новый любимый язык Groovy, вот более аккуратный пример того же самого:

import java.math.BigDecimal

def  first =   new BigDecimal("33.33333333333333")
def second = new BigDecimal("100")


println "result is " + first/second   // will print: result is 0.33333333333333
9
ответ дан 23 November 2019 в 23:54
поделиться

Если вы просто хотите обрабатывать значения в виде дробей, вы можете создать класс Fraction, который содержит поле числителя и знаменателя.

Напишите методы для сложения, вычитания, умножения и деления, а также метод toDouble. Таким образом, вы сможете избежать использования плавающих чисел во время вычислений.

EDIT: Быстрая реализация,

public class Fraction {

private int numerator;
private int denominator;

public Fraction(int n, int d){
    numerator = n;
    denominator = d;
}

public double toDouble(){
    return ((double)numerator)/((double)denominator);
}


public static Fraction add(Fraction a, Fraction b){
    if(a.denominator != b.denominator){
        double aTop = b.denominator * a.numerator;
        double bTop = a.denominator * b.numerator;
        return new Fraction(aTop + bTop, a.denominator * b.denominator);
    }
    else{
        return new Fraction(a.numerator + b.numerator, a.denominator);
    }
}

public static Fraction divide(Fraction a, Fraction b){
    return new Fraction(a.numerator * b.denominator, a.denominator * b.numerator);
}

public static Fraction multiply(Fraction a, Fraction b){
    return new Fraction(a.numerator * b.numerator, a.denominator * b.denominator);
}

public static Fraction subtract(Fraction a, Fraction b){
    if(a.denominator != b.denominator){
        double aTop = b.denominator * a.numerator;
        double bTop = a.denominator * b.numerator;
        return new Fraction(aTop-bTop, a.denominator*b.denominator);
    }
    else{
        return new Fraction(a.numerator - b.numerator, a.denominator);
    }
}

}
23
ответ дан 23 November 2019 в 23:54
поделиться

Компьютеры хранят числа в двоичном формате и не могут точно представлять такие числа, как 33,333333333 или 100,0. Это одна из сложностей при использовании двойников. Вам нужно будет просто округлить ответ, прежде чем показывать его пользователю. К счастью, в большинстве приложений такое количество десятичных знаков не требуется.

2
ответ дан 23 November 2019 в 23:54
поделиться

Числа с плавающей запятой отличаются от действительных чисел тем, что для любого заданного числа с плавающей запятой существует следующее более высокое число с плавающей запятой. То же, что и целые числа. Между 1 и 2 нет целого числа.

Невозможно представить 1/3 как число с плавающей запятой. Под ним есть поплавок, над ним - поплавок, и между ними есть определенное расстояние. И 1/3 находится в этом месте.

Apfloat для Java утверждает, что работает с числами с плавающей запятой произвольной точности, но я никогда не использовал его. Наверное, стоит взглянуть. http://www.apfloat.org/apfloat_java/

Аналогичный вопрос задавался здесь перед Библиотека высокой точности с плавающей запятой Java

2
ответ дан 23 November 2019 в 23:54
поделиться

Не тратьте усилия на использование BigDecimal. В 99.99999% случаев он вам не нужен. java double тип, конечно, приблизительный, но почти во всех случаях он достаточно точен. Имейте в виду, что у вас есть ошибка на 14-й значащей цифре. Это действительно ничтожно мало!

Для получения красивого результата используйте:

System.out.printf("%.2f\n", total);
-1
ответ дан 23 November 2019 в 23:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: