Hi,
After some operations
when i retrieve exception flags from FPU
it gives me invalid operation.
I want to know if it is infinity
or another case. Can i know the case ?
How to do that ?
In this particular case the factors are
X=3 and Y=11623334155587.786 and it seems
that the result is infinity
Thanks
Quote
fstsw ax ;retrieve exception flags from FPU
fwait
shr al,1 ;test for invalid operation
jc short _error
From the description of the Status Word,
QuoteBits 6-0 are flags raised by the FPU whenever it detects an exception. Those exception flags are cumulative in the sense that, once set (bit=1), they are not reset (bit=0) by the result of a subsequent instruction which, by itself, would not have raised that flag. Those flags can only be reset by either initializing the FPU (FINIT instruction) or by explicitly clearing those flags (FCLEX instruction).
Which means that if you check for an invalid operation at the end of a series of FPU instructions, that flag could have been raised by any of those previous instructions and not necessarily by the last one. When you need to find where the invalid operation occurs, you need to check for it after each operation which could be the culprit. If you are not entirely sure if an instruction could be the source of an invalid operation, you will have to verify its description; there are too many of those to list here.
A result of infinity would cause an Overflow exception but not always raise the Invalid Operation flag. Dividing by 0 would also raise the Divide-by-zero flag but not the Invalid Operation flag unless the value you are trying to divide is also 0.
raymond,
Thank you for reply
Quote
Which means that if you check for an invalid operation at the end of a series
of FPU instructions, that flag could have been raised by any of those
previous instructions and not necessarily by the last one.
No, i test each procedure that completes one operation.
We must assume that each procedure tests each result
in such a way that it is not possible to go to the
next one with Invalid Operation or Overflow. Quote
A result of infinity would cause an Overflow exception but not always
raise the Invalid Operation flag.
Here is the question.
When we have a lot of functions to process we need to have a good model.
It seems that we need to test
first
the Invalid Operation flag If it is an Invalid Operation, then
second we test the Overflow exception.
So one model is this:
Quote
fstsw ax ;retrieve exception flags from FPU
fwait
shr al,1 ;test for invalid operation
jc short _erro
;
; Ok, Go on
; ---------
...
clc
ret
;---------------
_erro: test ax, 0000100b
jnz _overflow
mov _ErrorZ, 1
stc
ret
_overflow: mov _ErrorZ, 2
stc
ret
I have one variable where i put the error code.
It is _ErrorZ which starts with 0.
_ErrorZ=0 means "undefined error".
All my procs exit with carry clear if no error
or carry set if error.
When the first procedure i call to solve an expression
exits we have 2 cases:
clc: we have the correct result
stc: we have the error code in _ErrorZ
One thing to you I learned a lot of things with your FPU lib.
As far as i know you never test overflow
but only "invalid operation".
In this particular problem it has something to do with
FpuXexpY. In fact, the problem is when i compute
XexpY. In your procedure you wrote this:
Quote
dest0:
fxch ;set up FPU registers for next operation
fyl2x ;->log2(Src1)*exponent
;the FPU can compute the antilog only with the mantissa
;the characteristic of the logarithm must thus be removed
fld st(0) ;copy the logarithm
frndint ;keep only the characteristic
fsub st(1),st ;keeps only the mantissa
fxch ;get the mantissa on top
f2xm1 ;->2^(mantissa)-1
fld1
fadd ;add 1 back
;the number must now be readjusted for the characteristic of the logarithm
fscale ;scale it with the characteristic
fstsw ax ;retrieve exception flags from FPU
fwait
shr al,1 ;test for invalid operation
jc srcerr ;clean-up and return error
Now,
i tested, and after
fscale i got
Overflow exception. And i thought why raymond didnt do
it ? I dont know if you want to do it or not but
i think the lib functions should exit with 2 error
codes: one for "Overflow" and the other to "invalid operation"
which means "undefined error". This 2 cases are not the
same thing. But ok, you do what you want to do.
It's all.
Ok, thank you :U
QuoteIn this particular case the factors are
X=3 and Y=11623334155587.786
Just curious. Where you trying to compute 3
11623334155587.786 or 11623334155587.786
3?
Quote
Just curious
Try to explain how do you write a procedure to compute
real1^real2^real3^...^realN
I want to know ! May be you test the exponent first
to see if it is 11623334155587.786 ! :P
Dont forget i wrote this also:
«After some operations
when i retrieve exception flags from FPU
it gives me invalid operation.»
Quotereal1^real2^real3^...^realN
Even that is ambiguous unless you use brackets. For example, 4^3^2 could be interpreted as either (4^3)^2=4
6 or 4^(3^2)=4
9And its obvious that if your exponent is large enough, you would get overflow but not necessarily an invalid operation at that point. You may get an invalid operation if you try to reuse the INFINITY value with other FPU instructions.
If you rely on the Fpulib to perform all your floating point computations, there is a function (FpuExam) to test if a parameter is effectively INFINITY if you have any doubt before proceeding with further computations.
Quote
Even that is ambiguous unless you use brackets. For example, 4^3^2 could be interpreted
as either (4^3)^2=46 or 4^(3^2)=49
It is not ambiguous ONLY because the calculator follows this rule:
First compute the last, or starts by the end.
So in the case 4^3^2: first 3^2=x, then 4^x.
Quote
you would get overflow but not necessarily an invalid operation at that point
Yes it is the same you told us in the previous post:
«A result of infinity would cause an Overflow exception but not always
raise the Invalid Operation flag»
I dont want to test Overflow first. Based on my example i want
to test Invalid Operation first. If is invalid i test Overflow.
Well if it is Overflow we get the message: Infinity;
If not we get simply ERROR.
Quote
You may get an invalid operation if you try to reuse the INFINITY value with other
FPU instructions.
If i get the overflow first it does not go to this case
Quote
If you rely on the Fpulib to perform all your floating point computations...
I am not using Fpulib but it is a reference
Quote
there is a function (FpuExam) to test if a parameter is effectively INFINITY
if you have any doubt before proceeding with further computations.
Could you explain why to use FpuExam after i get
first: Invalid Operation
and second: Overflow ?
If i get Overflow, i need to use FpuExam ?
Is it necessary ? We cannot assume it is INFINITY ?
Well (based on what you wrote) i used WhatCaseIsIt to see
what case is it after getting Invalid Operation and after
getting Overflow.
The result is this: positive Infinity !
So we dont need to use
fxam.
If you want know what is the expression i used in the calculator
to get this case, it is: 2^
3^log(2)^-e^+pi
log(2)^-e^+pi =
1162334155587.786Quote
WhatCaseIsIt proc
fxam ;examine it
fstsw ax ;copy the content of the Status Word to AX
fwait ;insure the last instruction is completed
sahf ;copy the C3/C2/C0 condition codes to the ZF/PF/CF flags
jz C3is1 ;either Zero, Empty or Denormalized if C3=1
jpe C2is1 ;either normal or infinity if C3=0 and C2=1
jc isNAN
;
fn MessageBox, hDlg, "Dont know", "WhatCaseIsIt", MB_OK
ret
; code for the case of a NAN, no need to check the sign
isNAN:
fn MessageBox, hDlg, "NAN", "WhatCaseIsIt", MB_OK
ret
; would be Infinity if C3=0, C2=1 and C0=1
C2is1:
jc isINFINITY ;would be Infinity if C3=0, C2=1 and C0=1
;this leaves the case for a Normal finite number
test ah,2 ;test for the sign which is in bit1 of AH
jnz negNORMAL
;code for the case of a positive Normal finite number
fn MessageBox, hDlg, "positive Normal finite number", "WhatCaseIsIt", MB_OK
ret
; code for the case of a negative Normal finite number
negNORMAL:
fn MessageBox, hDlg, "negative Normal finite number", "WhatCaseIsIt", MB_OK
ret
isINFINITY:
test ah,2 ;test for the sign which is in bit1 of AH
jnz negINFINITY
; code for the case of a positive Infinity
fn MessageBox, hDlg, "positive Infinity", "WhatCaseIsIt", MB_OK
ret
negINFINITY:
;code for the case of a negative Infinity
fn MessageBox, hDlg, "negative Infinity", "WhatCaseIsIt", MB_OK
ret
; ------------------
; Stop HERE with ret
; ------------------
C3is1:
jc isEMPTY ;would be Empty if C3=1 and C0=1
jpe isDENORMAL ;would be a Denormalized number if C3=1, C0=0 and C2=1
;this leaves the case for a Zero value
;code for the case of a Zero value, no need to check sign
fn MessageBox, hDlg, "Zero value", "WhatCaseIsIt", MB_OK
ret
isEMPTY:
;code for the case of an Empty register
;which does not apply in this example because
;ST(0) was loaded with a value from memory
fn MessageBox, hDlg, "Empty register", "WhatCaseIsIt", MB_OK
ret
isDENORMAL:
test ah,2 ;test for the sign which is in bit1 of AH
jnz negDENORMAL
;code for the case of a positive Denormalized number
fn MessageBox, hDlg, "positive Denormalized number", "WhatCaseIsIt", MB_OK
ret
negDENORMAL:
;code for the case of a negative Denormalized number
fn MessageBox, hDlg, "negative Denormalized number", "WhatCaseIsIt", MB_OK
ret
WhatCaseIsIt endp
Quote from: raymond on May 24, 2012, 01:02:24 AM
From the description of the Status Word,
QuoteBits 6-0 are flags raised by the FPU whenever it detects an exception. Those exception flags are cumulative in the sense that, once set (bit=1), they are not reset (bit=0) by the result of a subsequent instruction which, by itself, would not have raised that flag. Those flags can only be reset by either initializing the FPU (FINIT instruction) or by explicitly clearing those flags (FCLEX instruction).
Ray,
I am trying to raise an exception, but my FPU seems to like the little shock of dividing by zero - it just continues.
Olly says the mask bits are all cleared, so in principle it should trigger the exception. Is there any such CPU-specific behaviour? I have a Celeron M here...
Thanks for advice,
Jochen
include \masm32\include\masm32rt.inc
Near64 = 10000011b
.code
start: finit
push Near64*256
fldcw [esp] ; clear exception masks
pop eax
fldpi
fldz
fdiv ; 3.1415/0 -> should trigger exception
inkey "ok"
exit
end start
P.S.: I wonder if it is a hardware problem:
QuoteI had some old style PCs about 8 years ago that did not have the FPU interrupt correctly connected to the proper BIOS' interrupt handler that would do a BSOD. In the fast modern PCs, there is a completely different firmware software solution to catching the FPU exceptions which is controlled by a bit in CPU register CR0 (http://www.delphigroups.info/2/e0/483723-2.html)
Quote2^3^log(2)^-e^+pi
So you first get 3^log(2)^-e^+pi = INFINITY which raises the Overflow flag but not the Invalid Operation flag.
However, the next operation would then become 2^INFINITY, and
THAT raises the Invalid Operation flag.
Remember what I mentioned before?
QuoteYou may get an invalid operation if you try to reuse the INFINITY value with other FPU instructions.
If the Invalid Operation flag is raised at the END of a series of operations, I would suggest that the return answer should be INVALID (or UNDEFINED) regardless if the Overflow flag is raised. You should have a similar outcome as your example with the following example, but with the Divide-by-Zero flag being raised instead of the Overflow flag:
2^(3/(log(10)-1)) = 2^INFINITY
From a strictly math point of view, the actual result of your example is NOT infinity although it may be a very VERY
VERY large value. Only my example could be considered as being equal to infinity (without the Overflow flag being raised).
Jochen,
You must mean you were trying to get the FPU to generate an interrupt whenever a particular exception is detected.
From my tutorial, in the description of the interupt masks of the Control Word,
QuoteThis document will not describe how interrupts are generated and transmitted nor how to respond to such interrupts.
I haven't yet delved into that subject myself. Maybe I should in the near future, if only as an addendum to the tutorial.
This is not very well worked out or tested, and I didn't get to the infinity test, but it's a start.
Well i think you are thinking as if your procedure do the task and you are wrong.
1. This statement is wrong
Quote
So you first get 3^log(2)^-e^+pi = INFINITY which raises the Overflow flag
but not the Invalid Operation flag.
We should say:
Quote
We compute log(2)^-e^+pi and we get 1162334155587.786
Then, in the next step, when we try to compute 3^1162334155587.786
it raises the Invalid Operation flag
AND the Overflow flag is also set
2. This statement
is wrongQuote
However, the next operation would then become 2^INFINITY,
and THAT raises the Invalid Operation flag.
We should say simply
Quote
We have not NEXT OPERATION
Try to understand that i use this basic rule:
When i get "Invalid Operation" or "Overflow"
all computations are stoped
3. We are talking about FPU
Quote
From a strictly math point of view, the actual result of your example is ...
Well we need a statement like this:
Quote
From a strictly FPU point of view, the actual result of your example ...???
4.
Quote
You should have a similar outcome as your example with the following example,
but with the Divide-by-Zero flag being raised instead of the Overflow flag:
2^(3/(log(10)-1)) = 2^INFINITY
See point 2.
From a strictly FPU point of view i want to say that i dont know
what is the result of INFINITY * 0 or INFINITY/INFINITY
0/INFINITY etc.
Jochen,
Quote
Olly says the mask bits are all cleared, so in principle it should trigger the exception
I dont like to follow this way, so dont know why.
EDIT: If you want, i can post the procedure that does it and you
can analyse it
Quote from: MichaelW on May 25, 2012, 04:56:30 AM
This is not very well worked out or tested, and I didn't get to the infinity test, but it's a start.
Thanks, Michael. When stepping through your code and comparing it to mine, I finally found the reason why mine didn't trigger the exception: because fdiv memzero only sets the zerodivide exception
flag - the exception is triggered at the
next FPU instruction (and my code had no further FPU instructions).
A simple fstp st is sufficient.
Again, thanks for putting this together - one more lesson learnt :bg
I am trying to see why i get Invalid Operation AND the Overflow flag is set
Previous computation ? No. I call one procedure
but it doesnt set the overflow flag.
And, with or without FCLEX at the end of that procedure
"i get Invalid Operation AND the Overflow flag is set"
Thanks for this info Michael. Now I know where to start if I want to handle FPU exceptions myself, and then possibly explain such process in the tutorial.
Quote from: RuiLoureiro on May 25, 2012, 07:54:43 PM
I am trying to see why i get Invalid Operation AND the Overflow flag is set
Can you post the executable and tell us the exact condition when the exception happens? I could find out then with Olly.