ALT Linux Community general discussions
 help / color / mirror / Atom feed
* [Comm] g++ и неточности с плавающей точкой
@ 2008-04-07 18:30 Michael Pozhidaev
  2008-04-08 11:00 ` Sergey Vlasov
  0 siblings, 1 reply; 3+ messages in thread
From: Michael Pozhidaev @ 2008-04-07 18:30 UTC (permalink / raw)
  To: community

Привет всем!

Вопрос к знатокам глубин работы g++. Во время отладки порядочно нагромождённой 
программы на C++ обратил внимание на то, что результаты вычислений с плавающей точкой отличаются в зависимости от параметров оптимизации и отладки.
То, что получается при -g, отличается от того, что получается при -O2.
Вопрос в том, результат ли это недоглядок, вроде использования 
неинициализированных переменных или такое поведение нормально.
Можно ли добиться, чтобы вычисления всегда проходили стабильно или 
g++ явно генерирует различный код, приводящий к разным результатам даже на корректной программе?
-- 
С уважением и наилучшими пожеланиями, Михаил Пожидаев. E-mail: msp@altlinux.ru.
Томский государственный университет. Факультет информатики. http://www.csd.tsu.ru
AltLinux Team. http://www.altlinux.ru



^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [Comm] g++ и неточности с плавающей точкой
  2008-04-07 18:30 [Comm] g++ и неточности с плавающей точкой Michael Pozhidaev
@ 2008-04-08 11:00 ` Sergey Vlasov
  2008-04-08 13:43   ` Michael Pozhidaev
  0 siblings, 1 reply; 3+ messages in thread
From: Sergey Vlasov @ 2008-04-08 11:00 UTC (permalink / raw)
  To: community

[-- Attachment #1: Type: text/plain, Size: 3492 bytes --]

On Tue, Apr 08, 2008 at 01:30:31AM +0700, Michael Pozhidaev wrote:
> Вопрос к знатокам глубин работы g++. Во время отладки порядочно
> нагромождённой программы на C++ обратил внимание на то, что результаты
> вычислений с плавающей точкой отличаются в зависимости от параметров
> оптимизации и отладки.  То, что получается при -g, отличается от того,
> что получается при -O2.  Вопрос в том, результат ли это недоглядок,
> вроде использования неинициализированных переменных или такое поведение
> нормально.  Можно ли добиться, чтобы вычисления всегда проходили
> стабильно или g++ явно генерирует различный код, приводящий к разным
> результатам даже на корректной программе?

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

В архитектуре x86 регистры сопроцессора i387, используемые при
операциях с плавающей точкой, имеют разрядность 80 бит (что
соответствует типу long double).  Если производятся вычисления с типом
double, компилятор в зависимости от опций оптимизации может не
сохранять промежуточные значения в памяти (что привело бы к их
округлению до точности, обеспечиваемой 64-разрядным типом double), а
брать их из регистров сопроцессора (с сохранением 80-разрядной
точности); возможно, как раз это и является причиной изменения
результатов при смене флагов оптимизации.  У gcc есть опция
-ffloat-store, включение которой заставляет gcc сохранять все
промежуточные результаты вычислений с плавающей точкой в памяти, что
устраняет избыточную точность, но приводит к замедлению работы кода
из-за большого количества лишних команд пересылки между регистрами
сопроцессора и памятью.

Конечно, можно использовать для всех переменных тип long double, чтобы
все расчёты производились с максимально возможной точностью независимо
от того, будет ли компилятор сохранять промежуточные результаты в
памяти.  Однако такой код может менее эффективно работать на x86_64,
где по умолчанию операции с плавающей точкой выполняются через SSE2
(команды SSE2 поддерживают только float и double, а вычисления с long
double могут выполняться только с использованием команд i387).  Кроме
того, текущая версия valgrind не поддерживает эмуляцию точности long
double для i387 - при запуске под valgrind все операции с плавающей
точкой выполняются с точностью типа double, в результате поведение
программы может измениться.

Также есть возможность ограничить точность операций i387 через
соответствующие флаги управляющего слова - в <fpu_control.h>:

/* precision control */
#define _FPU_EXTENDED 0x300     /* libm requires double extended precision.  */
#define _FPU_DOUBLE   0x200
#define _FPU_SINGLE   0x0

Однако, судя по комментариям в этом файле, при включении такого
округления функции из библиотеки libm могут работать неправильно
(впрочем, под valgrind они как-то работают - возможно, в некоторых
случаях точность окончательного результата типа double будет ниже, чем
должна была бы получиться при 80-разрядных промежуточных переменных).

Наконец, если допустимо требование поддержки процессором команд SSE2,
можно собирать код с опциями -msse2 -mfpmath=sse - в этом случае
вычисления с типами float и double будут выполняться с помощью команд
SSE и SSE2, не использующих 80-разрядную точность.  На x86_64 эти
опции используются по умолчанию.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [Comm] g++ и неточности с плавающей точкой
  2008-04-08 11:00 ` Sergey Vlasov
@ 2008-04-08 13:43   ` Michael Pozhidaev
  0 siblings, 0 replies; 3+ messages in thread
From: Michael Pozhidaev @ 2008-04-08 13:43 UTC (permalink / raw)
  To: ALT Linux Community general discussions

Здравствуйте, Sergey Vlasov!

> В архитектуре x86 регистры сопроцессора i387, используемые при
> операциях с плавающей точкой, имеют разрядность 80 бит (что
> соответствует типу long double).  Если производятся вычисления с типом
> double, компилятор в зависимости от опций оптимизации может не
> сохранять промежуточные значения в памяти (что привело бы к их
> округлению до точности, обеспечиваемой 64-разрядным типом double), а
> брать их из регистров сопроцессора (с сохранением 80-разрядной
> точности); возможно, как раз это и является причиной изменения
> результатов при смене флагов оптимизации.  У gcc есть опция
> -ffloat-store, включение которой заставляет gcc сохранять все
О, просто блестящий совет! :)
Да, включение -ffloat-store выровняло вычисления. Сейчас это важнее,
чем экстремальная скорость. 
Уже собирался предпринимать поиски ошибок, 
но теперь порядок. По крайней мере понятно, что происходит, и насколько адекватные результаты получаются.
Большое спасибо.
-- 
С уважением и наилучшими пожеланиями, Михаил Пожидаев. E-mail: msp@altlinux.ru.
Томский государственный университет. Факультет информатики. http://www.csd.tsu.ru
AltLinux Team. http://www.altlinux.ru



^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2008-04-08 13:43 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-04-07 18:30 [Comm] g++ и неточности с плавающей точкой Michael Pozhidaev
2008-04-08 11:00 ` Sergey Vlasov
2008-04-08 13:43   ` Michael Pozhidaev

ALT Linux Community general discussions

This inbox may be cloned and mirrored by anyone:

	git clone --mirror http://lore.altlinux.org/community/0 community/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 community community/ http://lore.altlinux.org/community \
		mandrake-russian@linuxteam.iplabs.ru community@lists.altlinux.org community@lists.altlinux.ru community@lists.altlinux.com
	public-inbox-index community

Example config snippet for mirrors.
Newsgroup available over NNTP:
	nntp://lore.altlinux.org/org.altlinux.lists.community


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git