flat assembler
Message board for the users of flat assembler.
Index
> Main > Maybe another FPU bug 
Author 

LocoDelAssembly
The RC field (bits 11 and 10) or Rounding Control determines how the FPU will round results in one of four ways:
00 = Round to nearest, or to even if equidistant (this is the initialized state) 01 = Round down (toward infinity) 10 = Round up (toward +infinity) 11 = Truncate (toward 0) I tried with 2.5 and my pentium rounds to 2.0. I also tested with your values with the same result. With my bad English I understand by "even" a number with this property: x.y; if mod(x) = 0 then "even" Hope this helps [edit]ups sorry, here is the link http://www.website.masmforum.com/tutorials/fptute/fpuchap1.htm#cword [/edit] 

02 Aug 2005, 14:44 

MCD
round to nearest or to even if equidistant Sorry, that's exactly what I missed. I must have overreadden this. But this will make it a bit more harder to compute general round to nearest, as it is actually mostly used.


03 Aug 2005, 09:39 

LocoDelAssembly
MCD wrote: But this will make it a bit more harder to compute general round to nearest, as it is actually mostly used. I think if you add to the number to round 0.1 you can force to round up when the number is x.5 . The problem with this is when the number is x.5 or x.6, adding 0.1 before runding will rounds down the number so you will need to take care with that adding 0.1 in that case. If you find a solution please post 

03 Aug 2005, 14:40 

revolution
Quote: But this will make it a bit more harder to compute general round to nearest 

03 Aug 2005, 16:25 

Madis731
In math (that you learn in school) you round any number up to 0.4(9) to ZERO and >=0.5 to ONE. Its just agreed on. When you have 0.5 did any teacher tell you where to round ? Do you logically take ...hmm 1 or put bunch of numbers on i.e. xaxis and equally share every integer the same amount of ... "attention"?
I think if you add 0.000001 (single) or 1E12 (double) to any number and round it  you're OK! Other thing you might consider is adding 0.5 and truncating. Should give the same results. Why the last one works? When you got 3 floats: 0.5, ±0.0 and +0.5, you round them in your head and get 0,0,1 (equal share!). Now add 0.5 to each float resulting in ±0.0, +0.5, +1.0. You can already see what comes out after truncating. 

03 Aug 2005, 21:31 

revolution
Quote: I think if you add 0.000001 (single) or 1E12 (double) to any number and round it  you're OK Quote: adding 0.5 and truncating Last edited by revolution on 04 Aug 2005, 15:57; edited 1 time in total 

03 Aug 2005, 23:06 

LocoDelAssembly
My electronic calculator rounds x.5 to x1 and x.5 to x+1, if MCD needs this behavior he will need to add 0.5 before the truncation.
[edit]Add 0.5 when x is negative of course and add 0.5 if x is not negative[/edit] 

03 Aug 2005, 23:12 

LocoDelAssembly
MCD check this with OllyDbg:
Code: format PE GUI 4.0 finit fstcw [control] wait or [control], 0000110000000000b fldcw [control] mov ecx, 6 .loop: fld [nums+ecx*4] ftst fstsw ax fwait sahf sbb eax, eax fadd [_0.5+4+eax*4] frndint dec ecx jns .loop int 3 _0.5 dd 0.5, 0.5 nums dd 1.5, 1.0, 0.5, 0.0, 0.5, 1.0, 1.5 control dw ? BTW, why FASM inserts a WAIT after ftst? FASM also inserts a WAIT after FNINIT and if I use FINIT inserts a WAIT before FINIT too. I'm using FASM 1.62 

04 Aug 2005, 05:51 

MCD
You're correct locodelassembly, I already have used such rounding method, but it's just too slow
Anyway, for SSE you can do it easier with cvttinstructions. And actually, sometimes this little rounding issue DOES matter a lot, as the following FPU general exponentiating code shows (a^b = e^( ln(a) * b ) with fscale): Code: finit;init FPU to set rounding to round to nearest or even fld dword [esi+4];this is exponent b fld dword [esi];this is the base a fyl2x fld st frndint fsubr st,st(1) f2xm1 fld1 fadd fscale fstp st(1) fstp dword [edi];result a^b Unfortunately we have to use frndint, fscale and so on because FPU logarythm doesn't accept all values. So we need rounded value of exponent for fscale later. All seems to work good. But the problem arrises now if you calculate something like 100^1.5. In this case, the rounding method differs from usual math round to nearest, and a value, which is 1 to small is passed to the fscale, so we got the false result 100^1.5 = 500 instead of 100^1.5 = 1000. Unfortunately there is a work around, even without having to switch the FPU CW to truncate: Code: finit fld dword [esi+4] fld dword [esi] fyl2x fld st frndint ; fsubr st,st(1) fsub st(1),st;fixed fxch st(1) ;fixed f2xm1 fld1 fadd fscale fstp st(1) fstp dword [edi] This was the kind of buggy fpu calculation routine which made me running up the walls for hours _________________ MCD  the inevitable return of the Mad Computer Doggy __/ .+~ .  Last edited by MCD on 05 Aug 2005, 09:22; edited 3 times in total 

04 Aug 2005, 07:36 

Tomasz Grysztar
Use FNSTSW and FNINIT for the opcodes that don't do FWAIT  check out in Intel manuals.


04 Aug 2005, 10:11 

LocoDelAssembly
Opcode Instruction Description
9B D9 /7 FSTCW m2byte Store FPU control word to m2byte after checking for pending unmasked floatingpoint exceptions. D9 /7 FNSTCW* m2byte Store FPU control word to m2byte without checking for pending unmasked floatingpoint exceptions. You are right (as always), I thought putting a wait was responsibility of the coder and the wait version of the instructions are for wait for completeness. MCD, sorry I don't understand too much maths, I'm very bad and I loose some years in my career for that. 

04 Aug 2005, 14:22 

< Last Thread  Next Thread > 
Forum Rules:

Copyright © 19992020, Tomasz Grysztar. Also on GitHub, YouTube, Twitter.
Website powered by rwasa.