Подтвердить что ты не робот

Почему операции с плавающей точкой отображаются на разных языках?

Я прочитал:

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

test.js

#!/usr/bin/env node

var nine = 9.0;
var pointOhOhOne = 0.001;
var result = nine * pointOhOhOne;
console.log(result);

test.java

public class test {

  public static void main(String[] argv) {
    double nine = 9.0d;
    double pointOhOhOne = 0.001d;
    double result = nine * pointOhOhOne;
    System.out.println(result);
  }

}

test.c

#include "stdio.h"

int main() {
  double nine = 9.0;
  double pointOhOhOne = 0.001;
  double result = nine * pointOhOhOne;
  printf("%f", result);
}

test.rb

#!/usr/bin/env ruby

nine = 9.0
pointOhOhOne = 0.001
result = nine * pointOhOhOne

print result

test.py

#!/usr/bin/env python

nine = 9.0
pointOhOhOne = 0.001
result = nine * pointOhOhOne

print result

результаты:

ruby     0.009000000000000001
python   0.009
node     0.009000000000000001
java     0.009000000000000001
c        0.009000

gist: https://gist.github.com/reklis/6694ad5fb01991a79a1a

4b9b3361

Ответ 1

@ouah устанавливает, что все языки ведут себя одинаково. Мой ответ направлен на то, чтобы объяснить, почему они выглядят иначе. Единственными двумя языками, которые имеют "разные" выходные данные, являются C и Python.

Очевидно, что каждый язык, кроме C и Python, просто распечатывает значение float как можно больше десятичных знаков.

C легко объяснить. Вы используете printf("%f", result), не указав явное значение точности. По стандарту C точность спецификатора f по умолчанию равна 6. Таким образом, выводится ровно шесть знаков после запятой, что и есть то, что вы видите. Как отмечает @ouah, установка точности до 18 даст ожидаемый результат. Это потеря: удвоения, которые отличаются от 7-го десятичного разряда, будут распечатываться одинаково, и поэтому вывод %f нельзя использовать для точной реконструкции исходного поплавка.

Python немного сложнее. Python 3.1 представил новый алгоритм с плавающей запятой repr, основанный на работе Дэвида Гей. Проблема Python, соответствующая этой функции, находится здесь: http://bugs.python.org/issue1580. Эта функция также была включена в Python 2.7.

Цель этой новой функции заключалась в том, чтобы уменьшить путаницу в отношении плавающей запятой (хотя это и весьма полезно), и, что более важно, обеспечить более понятные для человека и более короткие представления чисел с плавающей запятой, не влияя на поведение в обратном направлении; то есть float(repr(x)) всегда равно x, даже если repr(x) сокращается из-за этого алгоритма. Таким образом, алгоритму удается создать более короткое представление с плавающей запятой, оставаясь без потерь: win-win!

Официальное описание говорит так:

Новый алгоритм для выражения (1.1) более умный и возвращает "1.1". Фактически, он ищет все эквивалентные строковые представления (те, которые хранятся с одним и тем же базовым значением float) и возвращает кратчайшее представление.

Ответ 2

В C на моей системе:

printf("%.18f\n", result);

0.009000000000000001

В Python в моей системе:

print("%.18f" % result)

0.009000000000000001

C или Python, как и другие языки, ограничивают количество десятичных цифр по умолчанию своими функциями печати. ​​