Ada_Ru форум

Обсуждение языка Ада

decimal floating point type

Оставить новое сообщение

Сообщения

Dmitriy Anisimkov
decimal floating point type
2004-05-07 09:15:01

В стандарте Ada95 как я понял, есть

двоичные типы с фиксированной и плавающей точькой.

а вот десятичные типы только с фиксированной точькой.

 

Не подскажите ли, где найти реализацию десятичьных чисел с плавающей точькой ?

 

В гугле нашел только описания алгоритмов и одну сишную библиотеку,

хотелось бы чего нибудь уже готового и на Ада.

 

Если не найду, придется либо биндиться, либо писать заново.

Dmitriy Anisimkov wrote:

В стандарте Ada95 как я понял, есть

двоичные типы с фиксированной и плавающей точькой.

а вот десятичные типы только с фиксированной точькой.

 

Не подскажите ли, где найти реализацию десятичьных чисел с плавающей точькой ?

 

В гугле нашел только описания алгоритмов и одну сишную библиотеку,

хотелось бы чего нибудь уже готового и на Ада.

 

Если не найду, придется либо биндиться, либо писать заново.

 

Что-то я не пойму зачем такое нужно. Ведь идея десятичнях чисел как раз заключается в арифметике с _гарантированной_ точностью. Как только попадается плавающая точка, говорить о _гарантированной_ точности просто невозможно. И тогда десятичная арифметика ничем не отличается от двоичной.

 

PS. Если я прапвильно помню, то обработку двоично-десятичных чисел с плавающей точкой могли производить только машины IBM S360 .. S390 в "родном" режиме. А после даже они перешли на стандартное представление IEEE.

 

 

-- Vadim Godunko

Vadim Godunko wrote:

 

Dmitriy Anisimkov wrote:

В стандарте Ada95 как я понял, есть

двоичные типы с фиксированной и плавающей точькой.

а вот десятичные типы только с фиксированной точькой.

 

Не подскажите ли, где найти реализацию десятичьных чисел с плавающей точькой ?

 

В гугле нашел только описания алгоритмов и одну сишную библиотеку,

хотелось бы чего нибудь уже готового и на Ада.

 

Если не найду, придется либо биндиться, либо писать заново.

 

Что-то я не пойму зачем такое нужно. Ведь идея десятичнях чисел как раз заключается в арифметике с _гарантированной_ точностью. Как только попадается плавающая точка, говорить о _гарантированной_ точности просто невозможно. И тогда десятичная арифметика ничем не отличается от двоичной.

 

PS. Если я прапвильно помню, то обработку двоично-десятичных чисел с плавающей точкой могли производить только машины IBM S360 .. S390 в "родном" режиме. А после даже они перешли на стандартное представление IEEE.

У меня конкретная задача, надо посчитать выигрышь при игре на валюту.

купил контракт по одной цене, продал по другой,

валюты разные цены разные контракты разные, я не знаю в каком интервале будут числа при вычислениях,

а точьности в 64 бита будет вполне достаточьно.

 

Десятичная арифметика всегда будет отличаться от двоичьной потому что десятичные дробные числа

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

 

И у меня есть конкретный пример, который считается по разному в двоичной и в десятичной арифметике.

в оракле есть десятичьные числа с плавающей точькой, есть с чем сравнить.

У меня конкретная задача, надо посчитать выигрышь при игре на валюту.

купил контракт по одной цене, продал по другой,

валюты разные цены разные контракты разные, я не знаю в каком интервале будут числа при вычислениях,

а точьности в 64 бита будет вполне достаточьно.

 

А Ada.Decimal тут не спасает?

Sergey I. Rybin wrote:

 

У меня конкретная задача, надо посчитать выигрышь при игре на валюту.

купил контракт по одной цене, продал по другой,

валюты разные цены разные контракты разные, я не знаю в каком интервале будут числа при вычислениях,

а точьности в 64 бита будет вполне достаточьно.

 

А Ada.Decimal тут не спасает?

 

Нет, там только

 

generic

type Dividend_Type is delta <> digits <>;

type Divisor_Type is delta <> digits <>;

type Quotient_Type is delta <> digits <>;

type Remainder_Type is delta <> digits <>;

 

procedure Divide

(Dividend : in Dividend_Type;

Divisor : in Divisor_Type;

Quotient : out Quotient_Type;

Remainder : out Remainder_Type);

 

А мне надо плавающую точьку и всю арифметику для нее.

Dmitriy Anisimkov wrote:

 

А мне надо плавающую точьку и всю арифметику для нее.

 

Слушай, а поищи в дебрях Ada.* У GNAT-а абсолютно точно была поддержка представления, используемого мэйнфреймами. Вот только не помню как оно называлось.

 

 

-- Vadim Godunko

Hello!

 

On Fri, 7 May 2004, Dmitriy Anisimkov wrote:

 

Sergey I. Rybin wrote:

 

>У меня конкретная задача, надо посчитать выигрышь при игре на валюту. >купил контракт по одной цене, продал по другой,

>валюты разные цены разные контракты разные, я не знаю в каком интервале >будут числа при вычислениях,

>а точьности в 64 бита будет вполне достаточьно.

 

 

 

>А Ada.Decimal тут не спасает?

 

 

 

Нет, там только

 

generic

type Dividend_Type is delta <> digits <>;

type Divisor_Type is delta <> digits <>;

type Quotient_Type is delta <> digits <>;

type Remainder_Type is delta <> digits <>;

 

procedure Divide

(Dividend : in Dividend_Type;

Divisor : in Divisor_Type;

Quotient : out Quotient_Type;

Remainder : out Remainder_Type);

 

А мне надо плавающую точьку и всю арифметику для нее.

 

Не побоюсь показаться грубым, но мне кажется, что вы, мои уважаемые собеседники, несёте _полнейшую_ чушь. К сожалению, я сейчас дал для прочистки мозгов всю свою литературу по Ada'е почитать детям своих друзей, поэтому не смогу приводить цитаты и точные ссылки на источники.

 

Теперь попытаюсь обосновать свою первую фразу:

 

1. Для решения поставленной задачи _плавающая_ арифметика не нужна и нигде в мире не используется. И именно потому, что она всегда приближённая. Наверное, общие подходы к решению экономических задач ( а это именно экономическая задача ) на Ada'е стоит посмотреть у Василеску.

 

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

 

type MONEY is delta 0.01 range 0.0 .. 1_000_000_000_000.00 ;

 

( или сколько там надо для 64 разрядов ).

 

2. На низком уровне ( куда заглядывать просто неприлично !) ) согласно Янгу фиксированные типы реализуются как _целые_, к которым приписан некий масштабный коэффициент, используемый при вводе/выводе и преобразовании типов. Как я понимаю, во внутреннем представлении переменные описанные как

 

type DOLLARS is delta 0.01 range 0.0 .. 1_000_000.0 ; type LIRAS is delta 1_000.0 range 0.0 .. 100_000_000_000.0 ;

JOHNS_PURSE : DOLLARS := 2.00 ;

MARIOS_PURSE : LIRAS := 200_000.00 ;

 

должны быть абсолютно идентичны ( если я не наврал с размером ).

3. Двоично-десятичное представление по образцу PL/1

 

FIXED DECIMAL

 

крайне неэффективно со всех точек зрения, кроме ввода/вывода.

 

 

Я надеюсь, что никого не обидел. С удовольствием прочитаю ваши возражения ( не стесняйтесь в выражениях в рамках норманивной лексики !) ).

 

Sincerely yours Cyril Sazonov

PS Упомянутые авторы аннотированы в Ru.Ada.Community FAQ.

Cyril Sazonov wrote:

 

А мне надо плавающую точьку и всю арифметику для нее.

 

Не побоюсь показаться грубым, но мне кажется, что вы, мои уважаемые

собеседники, несёте _полнейшую_ чушь. К сожалению, я сейчас дал для прочистки

мозгов всю свою литературу по Ada'е почитать детям своих друзей, поэтому не

смогу приводить цитаты и точные ссылки на источники.

 

Теперь попытаюсь обосновать свою первую фразу:

 

1. Для решения поставленной задачи _плавающая_ арифметика не нужна и нигде в

мире не используется. И именно потому, что она всегда приближённая. Наверное,

общие подходы к решению экономических задач ( а это именно экономическая

задача ) на Ada'е стоит посмотреть у Василеску.

 

Ada предоставляет для этого возможность определения вещественных типов с

фиксированной точкой, обеспечиваюших _абсолютную_ точность. В данном случае

можно описать такой тип:

 

type MONEY is delta 0.01 range 0.0 .. 1_000_000_000_000.00 ;

 

Все несколько сложнее.

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

Невозможно записать результат операции 1 / 3 с абсолютной точьностью

ни в двоичьной ни в десятичной системе исчисления. (а троичьная система исчисления встречается крайне редко ;-).)

 

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

Я имею конкретный пример, когда заданные исходные данные, запущенные в формулу

состаящую из умножений делений сложений и вычитаний дают расхождение в 1 цент

при вычислениях с плавающей точькой по основанию 2 и по основанию 10.

 

Конкретно у меня, из за неточьности промежуточьных вычислений окончательный результат

1.1350000 в десятичном исчислении

в двоичьном выглядел

1.134999999....

 

округление которого до 2 знаков после запятой давало

1.14 в первом случае

и

1.13 во втором.

 

конкретные числа сейчас не помню, но суть та же.

Если тебе интересно, пришлю полный пример, он сейчас на работе у меня.

 

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

или переполняются, если точьность промежуточьного результата достигает

определенных пределов.

 

У меня уже есть конкретная функция, котора считает как надо в десятичьных числах с плавающей запятой. Она реализована на PL/SQL в оракле, в котором есть числа с десятичьным представлением с плавающей точькой. А мне надо добится тех же результатов.

 

2. На низком уровне ( куда заглядывать просто неприлично !) ) согласно Янгу

 

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

Vadim Godunko wrote:

 

Dmitriy Anisimkov wrote:

А мне надо плавающую точьку и всю арифметику для нее.

 

Слушай, а поищи в дебрях Ada.* У GNAT-а абсолютно точно была поддержка представления, используемого мэйнфреймами. Вот только не помню как оно называлось.

Какое-то представление есть, я не понял какое, вот тут.

 

package Interfaces.Packed_Decimal is файлы i-pacdec.ad?.

 

но операций над ним что то не видать.

 

Кроме того моя проблема оказалась не там где я искал.

Оказывается библиотека оракла безцеремонно меняла режим точности мат. сопроцессона на 64 битный

когда как GNAT использует точность 80-ю, т.е. по максимуму.

 

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

Кому интересно почитайте вот тут.

 

http://www2.hursley.ibm.com/decimal/

Hello!

 

On Sat, 8 May 2004, Dmitriy Anisimkov wrote:

 

Cyril Sazonov wrote:

 

>А мне надо плавающую точьку и всю арифметику для нее.

 

 

 

>1. Для решения поставленной задачи _плавающая_ арифметика не нужна и нигде в >мире не используется. И именно потому, что она всегда приближённая. Наверное, >общие подходы к решению экономических задач ( а это именно экономическая >задача ) на Ada'е стоит посмотреть у Василеску.

 

>Ada предоставляет для этого возможность определения вещественных типов с >фиксированной точкой, обеспечиваюших _абсолютную_ точность. В данном случае >можно описать такой тип:

 

type MONEY is delta 0.01 range 0.0 .. 1_000_000_000_000.00 ;

 

Все несколько сложнее.

Абсолютной точьности не бывает, ни в десятичьном ни в двоичном

представлении.

 

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

 

 

Невозможно записать результат операции 1 / 3 с абсолютной точьностью ни в двоичьной ни в десятичной системе исчисления. (а троичьная система исчисления встречается крайне редко ;-).)

 

Ошибаешься. Этот результат записывается так: 0 и 1 в остатке.

 

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

 

Природа твоей задачи такова, что в ней _нельзя_ округлять вообще.

Я имею конкретный пример, когда заданные исходные данные, запущенные в формулу

состаящую из умножений делений сложений и вычитаний дают расхождение в 1 цент

при вычислениях с плавающей точькой по основанию 2 и по основанию 10.

 

Это концептуальная ошибка. Попробуй посчитать то же самое по тем же формулам, но в _целых_ центах, учитывая остаток при делении. Я полагаю, что и Oracle считает такие вещи так же.

 

Надо потрясти _старых_ бухгалтеров, которые считали ещё на счётах и "Железных Феликсах", на предмет алгоритмов. Они должны уметь работать с остатками от деления и без округлений.

 

Что касается потери точности и вылета в переполнение, то это вопрос порядка выполнкния операций и организации вычислений. Вспомни классический пример вычисления суммы N членов ряда вида:

 

1/1 + 1/2 + 1/3 + ... + 1/(N-1) + 1/N

 

при достаточно больших N -- в зависимости от "направления" расчёта результат сильно меняется.

 

Ты, просто, не с того бока подходишь к задаче -- нужен не инженерный взгляд, а бухгалтерский.

 

>2. На низком уровне ( куда заглядывать просто неприлично !) ) согласно Янгу

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

 

Так я и говорю, что типы с фиксированной точкой позволяют считать с высокой скоростью и без округления ( но с остатком ).

 

Наверное, правильный подход приведёт к написанию пакета с такой примерно спецификацией:

 

 

package MONEY is

 

type MONEY_VALUE is delta 0.01 range 0.00 .. 1_000_000_000_000.00 ;

type THE_MONEY is private ;

 

function "+" ( LEFT, RIGHT : THE_MONEY ) return THE_MONEY ;

function "-" ( LEFT, RIGHT : THE_MONEY ) return THE_MONEY ;

function "*" ( LEFT, RIGHT : THE_MONEY ) return THE_MONEY ;

function "/" ( LEFT, RIGHT : THE_MONEY ) return THE_MONEY ;

 

function "=" ( LEFT, RIGHT : THE_MONEY ) return BOOLEAN ;

function "<" ( LEFT, RIGHT : THE_MONEY ) return BOOLEAN ;

function "<=" ( LEFT, RIGHT : THE_MONEY ) return BOOLEAN ;

function ">" ( LEFT, RIGHT : THE_MONEY ) return BOOLEAN ;

function ">=" ( LEFT, RIGHT : THE_MONEY ) return BOOLEAN ;

 

function SET ( ITEM : MONEY_VALUE ) return THE_MONEY ;

 

procedure ADD_CACHE ( ITEM : in out THE_MONEY ; ADDON : in MONEY_VALUE ) ; procedure ADD_REST ( ITEM : in out THE_MONEY ; ADDON : in MONEY_VALUE ) ;

function OBTAIN_CACHE ( ITEM : THE_MONEY ) return MONEY_VALUE ; function OBTAIN_REST ( ITEM : THE_MONEY ) return MONEY_VALUE ;

private

 

type THE_MONEY is record

CACHE : MONEY_VALUE := 0.00 ;

REST : MONEY_VALUE := 0.00 ;

end ;

 

end MONEY ;

 

 

Sincerely yours Cyril Sazonov

Dmitriy Anisimkov wrote:

В стандарте Ada95 как я понял, есть

двоичные типы с фиксированной и плавающей точькой.

а вот десятичные типы только с фиксированной точькой.

 

Не подскажите ли, где найти реализацию десятичьных чисел с плавающей точькой ?

 

В гугле нашел только описания алгоритмов и одну сишную библиотеку,

хотелось бы чего нибудь уже готового и на Ада.

 

Если не найду, придется либо биндиться, либо писать заново.

 

Если надумаешь писать заново, то рекомендую почитать Currency Specification из спецификаций CORBA, выпущеных OMG (www.omg.org).

 

В ней присутствуют все необходимые операции с валютами: от сложения и вычитания до конвертации в другие валюты по состоянию на определенную дату.

 

Если ещё и выложить подобный пакет под GMGPL, то было-бы просто замечательно.

 

 

-- Vadim Godunko

On Fri, May 07, 2004 at 08:08:53PM +0700, Dmitriy Anisimkov wrote:

 

У меня конкретная задача, надо посчитать выигрышь при игре на валюту. купил контракт по одной цене, продал по другой,

валюты разные цены разные контракты разные, я не знаю в каком интервале будут числа при вычислениях,

а точьности в 64 бита будет вполне достаточьно.

 

Десятичная арифметика всегда будет отличаться от двоичьной потому что десятичные дробные числа

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

И у меня есть конкретный пример, который считается по разному в двоичной и в десятичной арифметике.

в оракле есть десятичьные числа с плавающей точькой, есть с чем сравнить.

 

Я тоже не понял зачем плавающая арифметика.

Если в формуле участвует валюта и курс, то все вроде должно

укладываться в фиксированную десятичную. Валюта - 2 знака

после запятой, курс - обычно 4-ре. Произведение валюты на курс

суть тоже валюта, но другая, т.е. тоже 2 знака после запятой.

Почему не хватает фиксированной точки?

 

У меня тоже были непонятки с фиксированной точкой:

 

with Ada.Text_IO; use Ada.Text_IO;

 

procedure Test_Dec is

type Dec is delta 0.0001 digits 9 range 0.0 .. 10000.00; --

for Dec'Machine_Radix use 10;

 

X : Dec := 1549.0;

Y : Dec := 2213.0;

begin

Put_Line (Dec'Image (X / Y));

Put_Line (Dec'Image (Dec'Round (X / Y)));

end Test_Dec;

 

X/Y должно получаться 0.7, а получается 0.6999.

Хотя если прикинуть, как бы это было сделанно в

целочисленной реализации становится понятно почему:

 

X = 15490000, Y = 22130000

X / Y = 15490000 / 22130000 * 10000 = 6999 => 0.6999

 

Потом нашел атрибут Round, с ним все работает как надо.

 

--

Максим Резник

Cyril Sazonov wrote:

 

Все несколько сложнее.

 

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

 

Абсолютная точность есть в целых числах. А, насколько я понимаю и меня в этом

пока даже не пытались разубедть, числа с фиксированной точкой и есть по своей

сути целые.

 

Невозможно записать результат операции 1 / 3 с абсолютной точьностью

ни в двоичьной ни в десятичной системе исчисления. (а троичьная система исчисления встречается крайне редко ;-).)

 

Ошибаешься. Этот результат записывается так: 0 и 1 в остатке.

 

не достаточно для точной записи результа.

0 и 1 в остатке даст 1/4 тоже, но 1/3 не равна 1/4.

Но я понял что ты хотел сказать.

 

 

Про арифметику с остатками я в курсе, спасибо за напоминание.

Я имел в виду арифметику по фиксированному основанию.

арифметика с остатками по сути то же что и запись чисел в виде

числитель/знаменатель, то есть это арифметика по произвольному основанию, писал я эту арифметику,

конечно же она абсолютно точная, когда используешь только + - * /.

но она тяжеловата, и не нужна мне для данной конкретной задачи.

 

<<

 

type THE_MONEY is record

CACHE : MONEY_VALUE := 0.00 ;

REST : MONEY_VALUE := 0.00 ;

end ;

 

 

Для абсолютной точности нужно помнить еще на что мы делили когда получили REST.

Иначе можно было бы просто прибавить Rest к Cache и не париться.

 

У меня реализация была примерно следующая

 

type Rational is record

Numerator : Integer;

Denominator : Positive;

end record;

Maxim Reznik wrote:

 

X/Y должно получаться 0.7, а получается 0.6999.

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

 

X = 15490000, Y = 22130000 X / Y = 15490000 / 22130000 * 10000 = 6999 => 0.6999

 

Потом нашел атрибут Round, с ним все работает как надо.

То что тебе он помог, не значит что аттрибут Round на все случаи жизни.

для расчета профит лоса иногда надо вычислять обратную цену

1/цена.

 

если я ограничус 4 знаками после запятой, то потеряю точность обращения цены

USDJPY она больше 100.

и я не могу заранее знать какие еще появятся цены на нынке.

Новое сообщение:
Страницы: 1

Чтобы оставить новое сообщение необходимо Зарегистрироваться и Войти