Точность десятичного числа в Java, C, C ++ и других - PullRequest
2 голосов
/ 17 января 2012

Допустим, у нас есть такой цикл (псевдокод)

double d = 0.0
for i in 1..10 {
    d = d + 0.1
    print(d)
}

В C с printf("%f", d) я получаю это:

0.100000
0.200000
0.300000
...
1.000000

В C ++ с cout << d я получаюэто:

0.1
0.2
...
1

В Java с System.out.println(d) я получаю это:

0.1
0.2
0.3 (in debug mode, I see 0.30000000000004 there but it prints 0.3)
...
0.7
0.799999999999999
0.899999999999999
0.999999999999999

Итак, мои вопросы таковы:

  1. Почему этот простой кодпечатается на Java так плохо и правильно в C?
  2. Как это ведет себя на других языках?

Ответы [ 3 ]

6 голосов
/ 17 января 2012

Почему этот простой код напечатан на Java так плохо и правильно на C?

Поскольку вы не сравниваете одни и те же операции, вы получите другой результат.

Поведение double одинаково для разных языков, поскольку оно использует аппаратное обеспечение для выполнения этих операций в каждом случае. Единственная разница заключается в методах, которые вы выбрали для отображения результата.

В Java, если вы запустите

double d = 0;
for (int i = 1; i <= 10; i++)
    System.out.printf("%f%n", d += 0.1);

печатает

0.100000
0.200000
0.300000
0.400000
0.500000
0.600000
0.700000
0.800000
0.900000
1.000000

Если вы запустите

double d = 0;
for (int i = 0; i < 8; i++) d += 0.1;
System.out.println("Summing 0.1, 8 times " + new BigDecimal(d));
System.out.println("How 0.8 is represented " + new BigDecimal(0.8));

вы получите

Summing 0.1, 8 times 0.79999999999999993338661852249060757458209991455078125
How 0.8 is represented 0.8000000000000000444089209850062616169452667236328125
6 голосов
/ 17 января 2012

Как ответили здесь , это не относится ни к какому языку.

См. Здесь: Что должен знать каждый программист об арифметике с плавающей точкой

Действительные числа бесконечны.Компьютеры работают с конечным числом битов (сегодня 32 бита, 64 бита).В результате компьютерная арифметика с плавающей точкой не может представлять все действительные числа.0.1 является одним из этих чисел.

Обратите внимание, что проблема связана не с Ruby, а со всеми языками программирования, потому что это происходит из того, как компьютеры представляют реальные числа.

2 голосов
/ 17 января 2012
  1. Из-за поведения процедур печати.0.1 не может быть точно представлен в двоичном формате с плавающей запятой.
  2. В Python:

    >>> print('%.20f' % (.1 * 8))
    0.80000000000000004441
    >>> d = .0
    >>> for i in xrange(10):
    ...  d += .1
    ...  print('%.20f' % d)
    ... 
    0.10000000000000000555
    0.20000000000000001110
    0.30000000000000004441
    0.40000000000000002220
    0.50000000000000000000
    0.59999999999999997780
    0.69999999999999995559
    0.79999999999999993339
    0.89999999999999991118
    0.99999999999999988898
    

    Но обратите внимание:

    >>> print('%.20f' % .8)
    0.80000000000000004441
    
...