Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.135.219.166] |
|
Страницы: (2) [1] 2 все ( Перейти к последнему сообщению ) |
Сообщ.
#1
,
|
|
|
Всем привет!
Хочу использовать 80-битный long double (Windows x86 и x64). И вообще чтобы все операции производились с использованием FPU с точностью 80 бит (ибо SSE не работает с 80 битами). Объявляю переменные как long double, задаю все возможные ключи, которые нашёл: g++ -mpc80 -mlong-double-80 -m80387 -s -O2 "test.cpp" -o "test.exe" Всё равно смотрю отладчик – FPU настроен на точность 64 бита Что не хватает? p.s. Можно, конечно, влепить в начало asm-вставку с изменением настроек точности на 80 бит, но неужели это единственный способ? Для чего тогда -mpc80 сделали? |
Сообщ.
#2
,
|
|
|
Наверняка окажется, что 80-битная точность не ГОСТирована теми-то и теми-то, а потому использование оной - исключительно желание того или иного компилятора.
|
Сообщ.
#3
,
|
|
|
Э-э-э, ну 64 бита мантиссы – это вообще-то и есть 80-битный формат.
|
Сообщ.
#4
,
|
|
|
Цитата Jin X @ Что не хватает? Все хватает вроде бы, ну и славян дело говорит . https://en.wikipedia.org/wiki/Long_double |
Сообщ.
#5
,
|
|
|
Qraizer, причём тут мантисса?
Про отладчик я ошибся (не знаю, что за глюк я поймал вчера), FPU настроен на 80 бит даже без опций. Но! Расчёты "внутри" (чтение/запись в локальные переменные) происходят с 64 битами. Смотрим: // t.cpp #include <cmath> int x; int main() { x = round(M_PI + x); return 0; } ... mov eax, DWORD PTR _x mov DWORD PTR [esp+20], eax fild DWORD PTR [esp+20] fld QWORD PTR LC0 faddp st(1), st fstp QWORD PTR [esp] call _round ... LC0: .long 1413754136 .long 1074340347 И никакие опции не помогают! Добавлено Вот, скажем, я не могу сделать так, чтобы корень вычислялся из 80-битного выражения, там идёт fstp qword и тут же fld qword с того же места (нафига?), а в x64 работа идёт через SSE2 (sqrtsd). points += sqrt((radius2 - (uint64_t)xi*xi)); |
Сообщ.
#6
,
|
|
|
А это тогда что?
Цитата Jin X @ Всё равно смотрю отладчик – FPU настроен на точность 64 бита Точность бывает 24, 53 или 64 бита. Какие форматы использует компилятор для репрезентации long double, к этому не имеет отношения. |
Сообщ.
#7
,
|
|
|
Цитата Qraizer @ Хорошо, пусть мантисса будет точностью, а всё вместе – размерностью или форматом. Хотя тут по-разному можно рассудить. Экспонента тоже указывает точность: 1E-1000 или 1E+1000 от мантиссы не зависит, а к точности (чисто математически) это тоже относится.Точность бывает 24, 53 или 64 бита. Какие форматы использует компилятор для репрезентации long double, к этому не имеет отношения. Но если брать маны Интела, то он называет мантиссу "precision". Но тот же GCC пишет: Цитата -mpc80 Set 80387 floating-point precision to 80-bit. Но смысл, который я доношу вроде понятен же – это главное. К тому же, я написал ниже, что всё же формат FPU выставляется в 80 бит, но внутренние расчёты идут в 64-х битах. Как это исправить, как заставить GCC считать ВСЁ в 80 битах? |
Сообщ.
#8
,
|
|
|
Всё он считать в 80 битах не будет. Только то, что имеет тип long double. У тебя в примерах нигде нет long double.
#include <cmath> long double x; int main() { x = round(M_PI + x); return 0; } fld TBYTE PTR _x fld TBYTE PTR LC0 faddp st(1), st fstp QWORD PTR [esp+8] fld QWORD PTR [esp+8] fstp QWORD PTR [esp] call _round fstp TBYTE PTR _x Добавлено round() нигде не принимает long double, т.к. для её работы – округления к целому – и double с головой достаточно. |
Сообщ.
#9
,
|
|
|
Цитата Qraizer @ Не соглашусь, не достаточно. И аналогичная ситуация с sqrt.round() нигде не принимает long double, т.к. для её работы – округления к целому – и double с головой достаточно. #include <iostream> #include <cmath> int main() { long long x = 999999999999999999; // чтобы показать, что число не превышает 64 бита :) long double n = x; x = round(n); std::cout << x << std::endl; x = trunc(n); std::cout << x << std::endl; x = sqrt(n); std::cout << x << std::endl; return 0; } 1000000000000000000 1000000000000000000 1000000000 А теперь убери 4 девятки и будет всё ок. Добавлено В Delphi такой проблемы нет... |
Сообщ.
#10
,
|
|
|
Решение найдено!
truncl, roundl, sqrtl |
Сообщ.
#11
,
|
|
|
Цитата Jin X @ Решение найдено! truncl, roundl, sqrtl А не в дебри ли Си-шной либы тебя понесло? lround, llround, ... есличо. long long std::llround( long double arg ); long double std::sqrt( long double arg ); long double std::trunc( long double arg ); |
Сообщ.
#12
,
|
|
|
По Стандарту целые значения могут быть преобразованы к вещественным, однако взаимоотношения разных типов равноправны. В <cmath> до С++11 лежат сигнатуры, только принимающие float, double и long double, т.е. они перегружены. Поэтому при использовании функций с целым аргументом компилятор неминуемо даст ошибку разрешения перегрузки. В C++11 были добавлен синопсис функций, принимающий интегральные значения, который должны кастоваться в double.
Jin X, используй long double. Компилятор не будет вместо тебя заменять double на long double. |
Сообщ.
#13
,
|
|
|
Цитата JoeUser @ Нормально А не в дебри ли Си-шной либы тебя понесло? Цитата JoeUser @ Да, это тоже интересно и в данном случае довольно уместно lround, llround, ... есличо. Цитата Qraizer @ Прикол в том, что мне нужно было извлечь корень из большого целого числа, получив целый результат (теорема Пифагора: x = sqrt(k*k - y*y)).Jin X, используй long double. Тогда что же получается? x = std::llround((long double)(k*k-y*y)) ? |
Сообщ.
#14
,
|
|
|
Ну да. x = std::round(std::sqrt(static_cast<long double>...)) Можно без std::. Наверное. Ну и чисто C-шные функции тоже допустимы конечно. С префиксами/постфиксами которые.
В Плюсах типы данных играют важную роль архитектуры приложения. Они в первую очередь – в отличие от C – определяют не представление данных, а свойства этих данных. Типом данных определяются свойства сущности и набор допустимых операций. Когда ты меняешь тип данных в C, ты главным образом меняешь репрезентацию сущности, когда то же ты делаешь в C++, ты меняешь её свойства. Не, бывает, конечно, что каст в C++ используется для смены репрезентации, куда ж без этого, но философия языка всё-таки заточена под высокий уровень абстракции. Отсюда пошёл тезис про то, что если в C++ программе много кастов, это плохая программа. Просто надо понимать, что не в самих кастах дело, не они как таковые "плохие", плохо, когда тебе приходится часто и много менять свойства сущностей, с которыми ты работаешь. Это обычно говорит о плохой и непродуманной архитектуре программы. В твоём случае плохо это или нет, я не знаю, тебе виднее. Но однозначно, что тебе нужно сменить свойство "целочисленный" сущности "число" на свойство "вещественный с высокой точностью". |
Сообщ.
#15
,
|
|
|
Да, забыл sqrt я вписать (и мне trunc нужен, но не суть)
p.s. Кстати, (long long)x чем-то отличается от truncl(x) (где x - long double)? Добавлено Ну или там static_cast<long long>(x)... Добавлено Цитата Qraizer @ А зачем мне считать всё в long double, когда у меня вся суть именно в получении целочисленного результата (long long/uint64_t), и только в этом одном месте используется long double? Я бы использовал с удовольствием какой-нибудь llsqrt, принимающий long long, но вроде нет такого... Но однозначно, что тебе нужно сменить свойство "целочисленный" сущности "число" на свойство "вещественный с высокой точностью". |