[x86, fpu] rounding
операции честные или где-то могли перепутать тип данных?
Обычные сложение и вычитание плавающих чисел.
IEEE-какой-то там, то, думаю, что нет

на какой странице стандарта ты это обнаружил?

C:
int A = 0;
assert(1/2 + A - A == 2^40);


Пример для этого я писал как раз на С, но всё-таки там имеется в виду возведение в степень.
Можно получить единицу:
>>> (2.0 ** 52 + 1).hex
'0x1.0000000000001p+52'
>>> 2.0 ** 52 + 1) - 0.5).hex
'0x1.0000000000000p+52'
типа вот он округлил к ближайшему числу с нулевым младшим битом.
>>> 2.0 ** 52 + 1) - 0.25).hex
'0x1.0000000000001p+52'
а вот — не округлил. Видимо, при округлении оно смотрит на ещё ровно один бит (что в общем-то правильно).
Не знаю, может быть можно как-то его обмануть, используя 80-битность чисел внутри сопроцессора и избирательно - fast fp model, но он же и их тоже наверное правильно округляет...

> при округлении оно смотрит на ещё ровно один бит
В стандарте на самом деле точно написано, что именно происходит при округлении.
Ну расскажи же уже, что же там написано!
Пример кода под gcc/x86

#include <stdio.h>
#include <math.h>
void _fpu_inline(void);
main
{
double A = pow( 2, 63 B = 0.5;
printf("before inline:\n\tB = %g,\n\tA = %g,\n\tB + A - A = %g\n", B, A, B + A - A );
_fpu_inline;
printf("after inline:\n\tB = %g,\n\tA = %g,\n\tB + A - A = %g\n", B, A, B + A - A );
}
.section .text,"ax"
.globl _fpu_inline
.type _fpu_inline,@function
.align 16
_fpu_inline:
finit
fstcw mem2
orw $0x800, mem2
andw $0xfcff, mem2
fldcw mem2
ret
.section .data
.align 64
mem2: .4byte 0x0

Вот, кому угодно, код для студии (а может и под gcc сработает).
#include <stdio.h>
#include <float.h>
#include <math.h>
int main
{
_controlfp( _RC_UP, _MCW_RC );
_controlfp( _PC_24, _MCW_PC );
float two40 = pow( 2.0f, 40.0f );
float A = pow( 2.0f, 63.0f );
printf( "%f\n", 0.5f + A - A - two40 );
return 0;
}
Для округления строятся два числа, влезающие в нужную точность, слева и справа от округляемого, и, в зависимости от параметров округления, округление идёт к одному из них. В данном случае данными числами будут 0 и 2^40 соответственно.Я не смог найти в драфте каким образом 1\2 может округлиться до 2^40.
Несколько раз просмотрел документ http://www.validlab.com/754R/nonabelian.com/754/comments/Q75...
Буду рад, если вы приведете ссылки на этот документ.
Из этого документа я понял, что округление применяется к infinitely precise number чтобы получить binary floating point format, описано 5 способов (tiesToEven, tiesToAway, towardPositive, towardNegative, towardZero) и каждый из них выбирает closest to initial number (пункты 6.2.1 + 6.2.2). Ближайшим к 1\2 ну никак 2^40 у меня не получается (1\2 замечательно представляется в виде float-a).
Далее переходим к операциям (глава 7 и пункт 7.4.1) и понимаем, что даже 1\2 не надо пытаться округлять, потому что округление делается _после_ применения операции formatOf-addition(source1, source2 то есть как бы выполняется infinitely precise сложение, а затем врубают алгоритм округления, чтобы уложиться в бинарный формат.
В общем, магия какая-то

Короче, ХЗ, что там в стандартах, но FPU в интеле, походу, думает, что (2^63 + 1/2) при включенном округлении вверх = (2^63 + 2^40).
Ну вроде никакой магии. Можно сначала выполнить infinitely precise add, но потом (1/2 + 2^63) всё равно не влезут в точность сингла. В этот момент мы округлим последний бит мантиссы до 1, что и будет 2^40.
при включенном округлении вверхи еще если заставить его вычислять это в single, не в double и не в double extended.
Для double и extended, думаю, можно аналогичные примеры придумать.


Не, ну не достаточно просто считать в типе float, надо еще соответствующие флаги выставить. Это действительно так очевидно?
все же не 1\2 округляют, а округляют сумму
спасибо
Оставить комментарий
lilia_rass
Возможно ли при каких-либо условиях равенство:1/2 + A - A == 2^40
Если да, то при каких.
(Всё по стандарту binary floating point IEEE-какой-то там)