AXForum  
Вернуться   AXForum > Microsoft Dynamics AX > DAX: Программирование
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск Все разделы прочитаны

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 05.04.2011, 15:46   #1  
raz is offline
raz
NavAx
Аватар для raz
NavAx Club
Лучший по профессии 2014
Лучший по профессии 2009
 
1,494 / 1065 (38) ++++++++
Регистрация: 22.07.2003
Адрес: МО
Еще один странный глюк
Имеем тестовый Job
X++:
static void Test_Job(Args _args)
{
    AmountCur         a,b,c,d,e,f,t1,t2;
    ;
    a = 13532.5;
    b = 100 / 2827;
    c = 2776851.86;
    d = 2776851.86;
    e = a / b;
    f = (a / b) / c * d;

    e = Currency::amount(e);
    f = Currency::amount(f);

    info(strfmt("%1", e));
    info(strfmt("%1", f));
}
Результат:
Цитата:
382 563,78
382 563,77
Т.е. получаем расхождение в копейку, обнаружено при сопоставлении.
Дело в этом куске:
X++:
b = 100 / 2827;
Если тут прописать:
X++:
b = 0.0353731871241599;
То результат:
Цитата:
Сообщение (15:46:14)
382 563,77
382 563,77
ЗЫ. DAX 3 KR1
Старый 05.04.2011, 16:01   #2  
MikeR is offline
MikeR
MCT
Аватар для MikeR
MCBMSS
Лучший по профессии 2015
Лучший по профессии 2014
 
1,628 / 627 (24) +++++++
Регистрация: 28.11.2005
Адрес: просто землянин
в 2009 такая же картина.
Мне кажется, что аксапта не хранит значения после четвертого знака после запятой.
__________________
Axapta book for developer
Старый 05.04.2011, 16:15   #3  
kornix is offline
kornix
MCP
MCBMSS
Злыдни
Ex AND Project
 
414 / 146 (5) +++++
Регистрация: 24.02.2009
Адрес: Санкт-Петербург
DAX 4.0 - такого глюка нет.
Результат одинаковый.

А у вас в EDT Amount свойство NoOfDecimals чему равно?

Последний раз редактировалось kornix; 05.04.2011 в 16:29.
Старый 05.04.2011, 16:27   #4  
S.Kuskov is offline
S.Kuskov
Участник
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
3,440 / 1775 (66) ++++++++
Регистрация: 28.04.2007
Адрес: Калуга
А в чём вопрос? Это очевидно, что в общем случае погрешность операций с плавающей запятой не позволяет ожидать абсолютно точный результат. Например следующий код я думаю будет выдавать одинаковый результат на любой версии.
X++:
info(strfmt("%1", num2str(1/3*3, 0, 16, 0, 0)));
Старый 05.04.2011, 16:36   #5  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,701 / 1195 (43) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
Надо смотреть не результат, а промежуточные данные

X++:
static void Test_Job(Args _args)
{
    AmountCur         a,b,c,d,e,f,t1,t2;
    ;
    a = 13532.5;
    b = 100 / 2827;
    c = 2776851.86;
    d = 2776851.86;
    e = a / b;
    f = (a / b) / c * d;

    info("a / b = " + num2str(a / b,0,16,1,0));
    info("(a / b) / c = " + num2str((a / b) / c,0,16,1,0));
    info("(a / b) / c * d = " + num2str((a / b) / c * d,0,16,1,0));
    info("round((a / b) / c * d, 0.01) = " + num2str(round((a / b) / c * d, 0.01),0,16,1,0));
}
Ни одна программа не может хранить бесконечные дроби. В любом случае, количество значащих цифр мантиссы будет ограничено некоторым фиксированным числом. Скорее всего, как и большинство продуктов Microsoft, действительные данные в памяти Axapta храняться с точностью до 16 значащих цифр (точнее, то 15,95). Как следствие, выражение вида

1/3 = 0,3333333333333333

Не может иметь "бесконечное" число 3, чтобы при последующем умножении на 3 получить ровно единицу. Будет число чуть меньше единицы. На сколько "чуть" зависит от того, сколько значащих цифр хранится в данной программной оболочке

Ну, и кроме того, важными являются правила округления. Система Axapta, очевидно, использует "стандартные" правила округления

В приведенном изначально примере вопрос стоит об округлении числа

382563.7749999999000000

В данном контексте, фактически, с точностью до 2 знака после запятой. Очевидно, это будет число

382563.77

Все в соответствии с правилами округления.
Старый 05.04.2011, 16:47   #6  
Poleax is offline
Poleax
Модератор
Аватар для Poleax
MCP
MCBMSS
Злыдни
 
1,353 / 595 (22) +++++++
Регистрация: 17.02.2005
Адрес: msk
Записей в блоге: 34
Варианты:
1) b = 0.0353731871241599;
e = 382563.7749999999;
f = 382563.7749999999;
2) b = 100 / 2827;
e = 382563.775;
f = 382563.7749999999;
Это имхо недостаток правила.
Если следовать правилу
Цитата:
Округление к ближайшему целому (англ. round) — наиболее часто используемое округление. Число в десятичной системе округляют до N-ого знака в зависимости от N+1 знака:
если N+1 знак < 5, то N-ый знак сохраняют, а N+1 и все последующие обнуляют;
если N+1 знак ≥ 5, то N-ый знак увеличивают на единицу, а N+1 и все последующие обнуляют.
То права воздействия на N имеет только цифра N+1.
Все остальные цифры в пролете
__________________

This posting is provided "AS IS" with no warranties, and confers no rights.

Последний раз редактировалось Poleax; 05.04.2011 в 17:33. Причина: N+1
Старый 05.04.2011, 17:09   #7  
raz is offline
raz
NavAx
Аватар для raz
NavAx Club
Лучший по профессии 2014
Лучший по профессии 2009
 
1,494 / 1065 (38) ++++++++
Регистрация: 22.07.2003
Адрес: МО
Цитата:
Сообщение от Владимир Максимов Посмотреть сообщение
В приведенном изначально примере вопрос стоит об округлении числа

382563.7749999999000000

В данном контексте, фактически, с точностью до 2 знака после запятой. Очевидно, это будет число

382563.77

Все в соответствии с правилами округления.
В том то и проблема, что для:
X++:
e = a / b;
Результат будет: 382563.78
Старый 05.04.2011, 17:30   #8  
AndyD is offline
AndyD
Участник
КОРУС Консалтинг
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
 
2,560 / 2479 (88) +++++++++
Регистрация: 20.08.2005
А вот так
X++:
f = (a / b) * d / c;
округленные значения будут одинаковы, но f != e.

Просто при вычислении выражения промежуточные итоги тоже получаеются с какой-то точностью и ошибка округления в конце концов приводит к такому результату
__________________
Axapta v.3.0 sp5 kr2
Старый 06.04.2011, 08:53   #9  
KiselevSA is offline
KiselevSA
Злыдни
Аватар для KiselevSA
Злыдни
Лучший по профессии 2015
 
958 / 333 (13) ++++++
Регистрация: 25.01.2002
Адрес: Москва
А что получится, если в формуле записать b = 100 / 2827.0?
__________________
люди...считают, что если техника не ломается, то ее не нужно ремонтировать. Инженеры считают, что если она не ломается, то нуждается в совершенствовании.
Старый 06.04.2011, 09:46   #10  
S.Kuskov is offline
S.Kuskov
Участник
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
3,440 / 1775 (66) ++++++++
Регистрация: 28.04.2007
Адрес: Калуга
Цитата:
Сообщение от raz Посмотреть сообщение
Если тут прописать:
X++:
b = 0.0353731871241599;
То результат: ....
Вот где вкралась неточность в ваших расчётах!
Переменная b, значение которой вы вычисляете как 100 / 2827 на самом деле инициализируется не 0.0353731871241599, а 0.3537318712415989e-1. это легко проверить
X++:
b = 100 / 2827;
info(num2str(10*b, 0, 16, 0, 0));
Дело в том что когда мы говорим о точности в 16 знаков после запятой, на самом деле имеются в виду 16 значащих цифр мантисы. Функция же num2str возвращает непосредственно первые 16 цифр после запятой, в момент преоброзования отбрасывая все невместившиеся значащие цифры и округляя 17 знак.

Интересно а есть ли в аксапте возможность преобразовать вещественное значение в строку без потери значащих разрядов (т.е в экспоненциальном формате)?

Последний раз редактировалось S.Kuskov; 06.04.2011 в 09:57.
Старый 06.04.2011, 09:52   #11  
AndyD is offline
AndyD
Участник
КОРУС Консалтинг
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
 
2,560 / 2479 (88) +++++++++
Регистрация: 20.08.2005
На самом деле, не важно, какое значение будет в b
Если переписать так
X++:
f = (a / b) * (d / c);
то f == e
__________________
Axapta v.3.0 sp5 kr2
Старый 06.04.2011, 10:00   #12  
S.Kuskov is offline
S.Kuskov
Участник
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
3,440 / 1775 (66) ++++++++
Регистрация: 28.04.2007
Адрес: Калуга
Цитата:
Сообщение от AndyD Посмотреть сообщение
На самом деле, не важно, какое значение будет в b
Если переписать так
X++:
f = (a / b) * (d / c);
то f == e
Ещё бы, ведь d == с
Старый 06.04.2011, 10:07   #13  
AndyD is offline
AndyD
Участник
КОРУС Консалтинг
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
 
2,560 / 2479 (88) +++++++++
Регистрация: 20.08.2005
Это просто еще одна иллюстрация к значениям промежуточных вычислений
X++:
1 / c * d != 1 * d / c != 1
в отличие от
X++:
1 * (d / c) == 1 / (c / d) == 1
PS Насчет 1 * d / c != 1 погорячился
__________________
Axapta v.3.0 sp5 kr2

Последний раз редактировалось AndyD; 06.04.2011 в 10:09.
Старый 06.04.2011, 11:12   #14  
raz is offline
raz
NavAx
Аватар для raz
NavAx Club
Лучший по профессии 2014
Лучший по профессии 2009
 
1,494 / 1065 (38) ++++++++
Регистрация: 22.07.2003
Адрес: МО
Можно теоретизировать что и чем инициализируется в тестовом джобе, однако в системе есть код, который приводит к расхождению на копейку сопоставленной суммы в валюте и сопоставленной суммы в основной валюте.

X++:
CustVendSettle.settleNow()
{
	....

	paym2Invoice = 100 / custVendTransOpenDebet.settleExchRate;

	....
	
	custVendTransCredit.settleAmountCur -= Currency::amount(settleAmountCur / paym2Invoice, custVendTransCredit.currencyCode);
	
	// так можно вылечить
	custVendTransCredit.settleAmountCur -= Currency::amount((settleAmountCur / paym2Invoice) / custVendTransCredit.amountCur * custVendTransCredit.amountCur, custVendTransCredit.currencyCode);

	....


	settleAmountMSTCredit   = Currency::amount(-(settleAmountCur / paym2Invoice) /
					custVendTransCredit.amountCur * custVendTransCredit.amountMST);
	
	custVendTransCredit.settleAmountMST  += settleAmountMSTCredit;

	....
}
DAX 3
Теги
округление

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Глюк RunBase (AX40sp2) Alexx7 DAX: Программирование 7 22.01.2010 10:59
DeadLock. Один сеанс - несколько процессов. Владимир Максимов DAX: Программирование 20 12.07.2008 11:02
Глюк автоматическое рассопопоставление Logger DAX: Функционал 4 14.07.2006 10:09
Enum: глюк? Gorlum DAX: Программирование 11 10.02.2006 07:43
Help! Странный глюк.. AfA DAX: Прочие вопросы 8 25.02.2004 23:58
Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 07:57.