2015-07-02 4 views
0
% expr 60.9-59.7 
1.1999999999999957 

по умолчанию Похоже, что в приведенном выше примере expr выводит результат операции с плавающей точкой в ​​более высокой точности, что он вычисляет.Управление выходной точности арифметики с плавающей точкой в ​​TCL

Для чего-то что просто я бы ожидать более разумный выход, такие как выход этой C++ код:

#include <iostream> 
int main() 
{ 
    double a = 60.9; 
    a -= 59.7; 
    std::cout << "double a = " << a << std::endl; 
    float b = 60.9; 
    b -= 59.7; 
    std::cout << "float b = " << b << std::endl; 
} 

Выходные:

double a = 1.2 
float b = 1.2 

Таким образом, вопросы:

Почему TCL выводит результат expr в более высокую точность, чем он их вычисляет, тем самым вызывая артефакты lsb?

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

+2

Это просто потому, что в C и C++ точность по умолчанию равна 6, поэтому после округления до 6 десятичных цифр, 1.1999999 ... станет 1.2. Это не потому, что tcl вычисляет более высокую точность –

ответ

0

This answer указывает, что для C++ эта проблема также возникает.

У вас нет контроля над значением результата. Вы хотите, чтобы контролировать, как вы выводите его:

% expr 60.9-59.7 
1.1999999999999957 
% puts [format {%.2f} [expr {60.9-59.7}]] 
1.20 
2

Существует глобальная переменная, которая определяет, сколько места точности Tcl использует при преобразовании в строку: tcl_precision. Однако, глядя на этот ответ, я обнаружил, что с тех пор я использовал его, что он устарел, и что управление отображением с использованием команды format предпочтительнее. См. http://wiki.tcl.tk/1650 для получения подробной информации о том, как его использовать и почему вы не должны.

Обратите внимание, что у вас будет такая же проблема с C++; это проблема с IEEE-форматом чисел с плавающей запятой, а не с Tcl. «Избыточная» точность, о которой вы жалуетесь, - это просто эффект отображения точного значения выхода без его форматирования в соответствии с вашими потребностями. Разница между C/C++ & Tcl заключается в том, что по умолчанию точность форматированного вывода C составляет 6 цифр.

0

Арифметика с плавающей запятой выполняется по времени выполнения Tcl, который скомпилирован из C. Он работает точно так же, как арифметика с плавающей запятой, в любом другом исполняемом файле, скомпилированном из C/C++. Однако в Tcl, в отличие от C/C++, строковое представление может быть использовано для дальнейших вычислений *, а это означает, что произвольная потеря точности будет Bad Thing.

Вы можете заменить обычную команду puts командой, которая в основном выглядит так (просто доказательство концепции: на практике вам понадобится немного больше инфраструктуры для 1) иметь дело с дополнительными аргументами, чтобы 2) избежать этого работает по-разному в puts -capturing оболочек, и 3), чтобы вернуть некоторый контроль над этим для программиста, но это вполне возможно):

proc _puts str { 
    if {[string is double -strict $str]} { 
     puts [format %g $str] 
    } else { 
     puts $str 
    } 
} 

Это напечатает закругленные чисел с плавающей запятой по умолчанию.

*) Начиная с нескольких десятилетий назад, код Tcl байт-скомпилирован для использования фактических значений с плавающей запятой, хранящихся вместе с их строковыми представлениями, но компилятор все еще поклоняется пожеланиям программиста, если они решат пойти с s.r. по какой-то причине. Способность доверять s.r. быть «без потерь» является частью контракта между языком и программистом и вряд ли изменится.

Смежные вопросы