Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.142.195.24] |
|
Страницы: (3) 1 [2] 3 все ( Перейти к последнему сообщению ) |
Сообщ.
#16
,
|
|
|
Попробую сделать так:
__asm { MOV EAX, 0x1332; PUSH EAX; FLDCW [ESP]; POP EAX; } Сейчас нет возможности проверить, т.к. винда 64 бита. Добавлено Спасибо всем заранее. |
Сообщ.
#17
,
|
|
|
Цитата Abraziv @ Попробуйте 0x133F, т.к. это замаскирует все ошибки, и исключения при ошибках вызываться не будут. Но вообще, если причина в этом, значит либо в коде DLL ошибка, либо ей передаются неверные данные, которые не проверяются.Попробую сделать так В 32-битных программах соглашений куча. И они могут быть другими в Borland'е (и Borland - это что: Builder, Delphi...?) А в какой винде запускается 32-битная прога (x86 или x64) разницы быть не должно. Если возникает ошибка только в x86, то это странно. Почему не хотите прислать DLL и код, который его вызывает (рабочий - борландовский и MSVSCP)? Мы бы могли посмотреть в отладчике что происходит, а не гадать на кофейной гуще. И что вообще эта функция должна делать? Может, там вообще глюк из разряда: нужно передать Double через 2 даблворда в стеке, а он передаётся через ссылку... p.s. CW - управляющее слово только, а не кодовое Добавлено Только сейчас увидел сообщение в личке... |
Сообщ.
#18
,
|
|
|
Вангую переполнение стека FPU.
|
Сообщ.
#19
,
|
|
|
В общем, ситуация следующая...
DLL-функция вызывает функцию Trunc(X), которая удаляет дробную часть числа. Результат возвращается в виде 64-битного целого. Код этой функции таков: add esp,FFFFFFF4 wait fnstcw word ptr ss:[esp] wait mov al,byte ptr ss:[esp+1] or byte ptr ss:[esp+1],C fldcw word ptr ss:[esp] fistp qword ptr ss:[esp+4] mov byte ptr ss:[esp+1],al fldcw word ptr ss:[esp] mov eax,dword ptr ss:[esp+4] mov edx,dword ptr ss:[esp+8] add esp,C ret Так вот, каждый раз туда передаётся число, вдвое больше предыдущего (с вычетом единицы). В определённый момент (на последнем цикле) значение этого числа выходит за рамки 64 битного знакового числа, fistp помечает соответствующие биты в SW (status word) о том, что произошла исключительная ситуация, однако исключения сразу не происходит (оно происходит при вызове fwait и т.п. инструкций, в т.ч. после fldcw). И тут попадается fldcw, и возникает исключение. Почему только в 32-битной Windows? Потому что в 64-битной Windows CW=027F, в 32-битной CW=1272 (по крайней мере, в 7-ке, все вопросы к мелкомягким и их VSC++). Т.е. в 32-битной не замаскировано исключение #IA (invalid arithmetic), которое возникает при записи слишком большого значения как целого. Что делать? Вызывать finit из основной проги перед вызовом функции armInit Или выполнять такой код: short CW, CWnew; __asm { fnstcw CW fnstcw CWnew or CWnew, 1 // можно сделать or CWnew,0x3F для надёжности :) fldcw CWnew } amrInit(0); __asm fldcw CW Добавлено Ну или так: __asm { push eax fnstcw [esp] push eax fnstcw [esp] or [esp], 1 fldcw [esp] pop eax } amrInit(0); __asm { fldcw [esp] pop eax } |
Сообщ.
#20
,
|
|
|
В таком случае это не проблема ОСи. Trunc() не должна сообщать о проблеме, т.к. от проебразования к unsigned __int64 требуется беззнаковый результат, значит коли это происходит, Trunc() реализована неверно.
|
Сообщ.
#21
,
|
|
|
А это и не проблема оси. Это проблема MSVCPP, потому что на момент старта программы CW=027F как в 32 битах, так и в 64-х. И прога его меняет его ещё до вызова mainCRTStartup в зависимости от битности винды...
|
Сообщ.
#22
,
|
|
|
Цитата Jin X @ Хм. Это проблема MSVCPP, потому что на момент старта программы CW=027F как в 32 битах, так и в 64-х. И прога его меняет его ещё до вызова mainCRTStartup в зависимости от битности винды... Visual Studio 2015: Цитата _control87, _controlfp, __control87_2 И насколько я помню, так было всегда. Кто-то однозначно неправ. По умолчанию библиотеки времени выполнения маскируют все исключения для операций с плавающей запятой . Добавлено Попробую ещё раз вангануть: dll имеет и другие проблемы, по крайней мере с совместимостью. |
Сообщ.
#23
,
|
|
|
Цитата Qraizer @ Ну, скорее всего, да.Попробую ещё раз вангануть: dll имеет и другие проблемы, по крайней мере с совместимостью. Пустой проект показывает нормальный CW (027F) к моменту mainCRTStartup... |
Сообщ.
#24
,
|
|
|
Переписать код. Видишь ли, var = (unsigned __int64) (pow(2.0, (double) k) - 1.0); работает – если работает – по чистой случайности. FPU не имеет беззнаковых типов, даже целочисленных. При сохранении в квадрословное целое FPU всегда сохраняет его как знаковое. Если подать ему 263, то будет фиксироваться переполнение, о котором сообщается через IA. Если оно замаскировано, то маскированной реакцией является возврат целочисленной неопределённости, которая имеет вид минимально возможного (знакового) целого, т.е. 0x8000000000000000. И оно по чистой случайности совпадает с 263 в беззнаковом целом формате.
|
Сообщ.
#25
,
|
|
|
NaN – это нечисло. Думаю, этого достаточно, чтобы понять абсурдность желания. NaN появляется в вычислениях, которые невозможно вычислить. Они не имеют результата. Даже если поделить 123 на 0, будет не NaN, а всего лишь INF, с которым в принципе можно продолжать вычисления. При делении 0 на 0 будет NaN.
Если твоему алгоритму подходят выражения без результата, то мне сложно представить, что полезного такой алгоритм в состоянии предложить. |
Сообщ.
#26
,
|
|
|
Цитата Qraizer @ Видишь ли, var = (unsigned __int64) (pow(2.0, (double) k) - 1.0); работает – если работает – по чистой случайности. ... Если подать ему 263, то будет фиксироваться переполнение С чего это? В соответствии с выражением к целому должно приводиться не 263, а 263-1.0 = _I64_MAX. Может просто ms-оптимизатор тупит, заменяя вещественное вычитание целочисленным? |
Сообщ.
#27
,
|
|
|
leo, Qraizer, вы оба правы, только есть нюанс: точность.
Оптимизатор не тупит, всё нормально. В Trunc передаётся уже 263-1, но! Мантисса FPU (при 80-битной точности) содержит 63 бита (без знака). 263-1 – это ещё 63 бита, а вот 263 – уже 64. После pow результат содержит число 263, после него идёт вычитание единицы (fsub), вот только вычесть эту единицу он не может, т.к. точности не хватает, и там остаётся 263. И при преобразовании в unsigned __int64: Цитата Qraizer @ оно по чистой случайности совпадает с 263 в беззнаковом целом формате Добавлено Хотя результат по задумке должен быть 263-1... так что, уж не знаю в какой момент эта DLL-ка глюканёт при дальнейшей работе... Добавлено Вспоминается статья про Закон дырявых абстракций... Как раз в тему... |
Сообщ.
#28
,
|
|
|
Хотя, нет, немного не так... FPU нормально вычитает единицу из 263 при точности FPU-операций в 80 бит, результат же умещается в 63 бита. Проблема в другом: CW=1272 в 32 битах и CW=027F в 64 битах. А это вычисления с точностью double, т.е. 64 бита (где составляет 52 бита без учёта знака), т.е. результат будет неверным (без вычета единицы) значительно раньше, чем на последнем цикле. Так что, решить первоначальную проблему лучше изменением в CW не младшего бита, а установкой значения 3 в битах 8-9:
__asm { push eax fnstcw [esp] or word ptr [esp],0x300 // если ошибки всё же будут возникать (уже в другом месте), можно заменить 0x300 на 0x301, но тогда будет потеря точности вычислений (местами весьма серьёзная)... но такого быть уже не должно fldcw [esp] pop eax } amrInit(0); Тогда и результаты вычислений будут верными... |
Сообщ.
#29
,
|
|
|
Спасибо за ответ. Огромное спасибо. Сейчас буду тестировать. После отпишусь. Скажу сразу же, прога не падает после асм вставки.
|
Сообщ.
#30
,
|
|
|
Цитата Jin X @ Мантисса FPU (при 80-битной точности) содержит 63 бита (без знака)... Учти, что вычисляется степень двойки, а двоичная мантисса любого числа 2N строго равна 1 и представляется абсолютно точно в любом вещественном формате. Не знаю, как в билдере и мсвс, а в дельфях math.Power(..) для целых степеней считается через IntPower методом умножения, поэтому число 263 должно вычисляться абсолютно точно с мантиссой строго равной 1 без всякого дребезга в младших разрядах. |