Я задал следующий вопрос на форуме «Ask Ubuntu», и мне сказали, что этот вопрос не подходит для этого форума. Было предложено задать свой вопрос здесь. Я заранее прошу прощения, если это не подходящее место для этого вопроса.
В настоящее время я использую Java в качестве языка по умолчанию. Также в настоящее время я использую Kubuntu версии 12.04. Я конвертировал программу на c ++ в java, и результаты из программы java не совпадали с результатами из программы c ++. Я начал искать проблему, когда понял, что Java-программа дает правильные результаты, а программа C ++ не дает правильных результатов. Мой вопрос: может кто-нибудь объяснить, почему c ++ дает ошибочные результаты и можно ли это исправить?
Я написал две минимальные программы, чтобы проиллюстрировать проблему. Я также написал файл сценария для отображения двух программ, их компиляции и запуска. Результаты ниже. Очевидно, что значащие цифры находятся в одном и том же районе, однако при работе с большими степенями 10, такими как 30-я степень, разница значительна. Вот результаты моих тестовых программ и скриптов:
Linux Pegasus 3.2.0-54-generic # 82-Ubuntu SMP Вт 10 сентября 20:08:42 UTC 2013 x86_64 x86_64 x86_64 GNU / Linux
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
double testValue;
//---------------------------------------------------------------------
testValue = 1.0e0 * 1.9891e30;
cout << scientific << showpoint << right << setprecision(20)
<< "The test value = "<< setw(25) << testValue
<< " the test value should be 1.9891e30\n"<< endl;
return 0;
}
class test
{
public static void main (String[] args)
{
double testValue;
//---------------------------------------------------------------------
testValue = 1.0e0 * 1.9891e30;
System.out.format
(
"The test value = %.20e the test value should be 1.9891e30%n", testValue
);
} // end main
}
Тестовое значение = 1.98909999999999988781e + 30 тестовое значение должно быть 1.9891e30
Тестовое значение = 1.98910000000000000000e + 30 тестовое значение должно быть 1.9891e30
Очевидно, что значение testValue, созданное программой c ++, неверно, в то время как значение testValue, созданное программой java, является правильным. Любое понимание этой проблемы будет высоко оценено. Я искал в Google и здесь с помощью поисковых терминов «ошибочные вычисления C ++» без каких-либо существенных находок.
Я не уверен, как вы считаете, что это вычисление было ошибочным? Математика с плавающей точкой подвержена небольшим различиям в значениях. На одном компьютере с одним компилятором значения с плавающей запятой являются детерминированными, однако при использовании разных языков и разных компиляторов вы не гарантируете одинаковые результаты.
Мой старый профессор Брюс Доусон дает отличный обзор:
http://randomascii.wordpress.com/2012/04/05/floating-point-complexities/
http://randomascii.wordpress.com/2013/07/16/floating-point-determinism/
Результаты, которые вы видите выше, выглядят просто отлично для меня. Возможно, вам следует округлить до 3 цифр после десятичной точки и использовать это для сравнения полученных значений. С плавающей точкой вам будет трудно получить более точную информацию между различными языками и компиляторами.
Кроме того, я бы порекомендовал «неточность с плавающей точкой» в качестве лучшего поиска Google в следующий раз.
Код C ++ печатает фактическое значение, в то время как код Java округляет значение. Имейте в виду, что число 0.0001
как только 0.1
не может быть представлен точно в двоичном виде.
Вы можете получить его, чтобы напечатать фактическое значение с BigDecimal
который будет таким же, как ваш вывод C ++:
import java.math.*;
class test
{
public static void main (String[] args)
{
double testValue;
testValue = 1.0e0 * 1.9891e30;
BigDecimal realvalue = new BigDecimal(testValue);
System.out.format
(
"The test value = %.20e the test value should be 1.9891e30%n", realvalue
);
}
}
Выход
Тестовое значение = 1.98909999999999988781e + 30 тестовое значение должно быть
1.9891e30
НАСКОЛЬКО МНЕ ИЗВЕСТНО, double
в C ++ и Java оба будут содержать так же значение, но при печати их, вы видите разницу.