### Author Topic: Large integers and floats  (Read 18075 times)

#### JK

• Member
• Posts: 156
##### Re: Large integers and floats
« Reply #60 on: October 01, 2021, 05:22:06 AM »
Sorry JJ, no - not old problems. I know about the problems comparing floats.

My problem is about initializing floats. I want to be able to initialize a real4, a real8, a real10 and a real16 with a floating point number (e.g. "17.6") and these initialized reals should then compare equal. Using the built-in initializing feature makes these reals slightly different (see code above), because each real gets assigned the floating point number with the corresponding precision. Basically this is not wrong, but in effect it makes these reals different when compared.

Ok, i could first define a real4 = 17.6, load this real4, convert it to real8, real10 and real16 and save the result as real8, real10 and real16. This would be workaround, but it would be nice to be able to do it, when defining the real4/8/10/16, which currently is possible only using real hex numbers. But these numbers have to be looked up (e.g with a debugger) or calculated (somehow), which is not very practicable. Something built-in or a macro would be perfect - any ideas?

JK

#### mineiro

• Member
• Posts: 810
##### Re: Large integers and floats
« Reply #61 on: October 01, 2021, 08:09:15 AM »
This simple code was done to static real4 17.6; a string parser/converter and more work is necessary. I was thinking in dealing with integers.
Code: [Select]
`;fractional part  1/10,1/100,1/1000,...;                  0,1   0,01    0,001 ...mov rax,6           ;?.6mov ecx,10cvtsi2ss xmm0,eax   ;cvtsi2sdcvtsi2ss xmm1,ecx   ;cvtsi2sddivss xmm0,xmm1     ;divsd , 0.6;integer partmov eax,1           ;17 = 1*10^1 + 7*10^0mov ecx,10          ;1,10,100,1000,...cvtsi2ss xmm1,eaxcvtsi2ss xmm2,ecxmulss xmm1,xmm2mov eax,7cvtsi2ss xmm2,eaxaddss xmm1,xmm2;integer part xmm1 + fractional part xmm0addss xmm0,xmm1     ;17.0 + 0.6movd eax,xmm0       ;eax=418ccccdh`
I'd rather be this ambulant metamorphosis than to have that old opinion about everything

#### jj2007

• Member
• Posts: 11768
• Assembler is fun ;-)
##### Re: Large integers and floats
« Reply #62 on: October 01, 2021, 08:52:49 PM »
I want to be able to initialize a real4, a real8, a real10 and a real16 with a floating point number (e.g. "17.6") and these initialized reals should then compare equal.

That's an interesting idea, and here is an example that "approaches" a REAL4 to its REAL8 equivalent:

Code: [Select]
`SevenTeenPointSix4 REAL4 17.59999942779541193265 ; -> 17.600000381469726560SevenTeenPointSix8 REAL8 17.6`
However, it doesn't solve the problem that the inherent precision of a REAL4 is lower, and therefore an "equal" comparison is not possible. You need to define a precision for the comparison, too. Attached a demo using Fcmp. You will see that the 17.599... Real4 is very close to the 17.6 Real8 but still, surprise surprise, "greater".

#### JK

• Member
• Posts: 156
##### Re: Large integers and floats
« Reply #63 on: October 01, 2021, 11:47:54 PM »
Quote
However, it doesn't solve the problem that the inherent precision of a REAL4 is lower, and therefore an "equal" comparison is not possible
Sorry, but this is not quite true, see the following (ASMC) code:
Code: [Select]
`option wstring:ONinclude windows.inc includelib kernel32.lib includelib user32.lib .data;*************************************************************************************; 1st try;*************************************************************************************g_r4  real4  17.6g_r8  real8  17.6g_r10 real10 17.6;*************************************************************************************; 2nd try;*************************************************************************************;g_r4  real4  418CCCCDr;g_r8  real8  418CCCCDr;g_r10 real10 418CCCCDr.codestart proc ;***************************************************************************; main;***************************************************************************local l_r4 :real4local l_r8_1 :real8local l_r8_2 :real8local l_r10 :real10  finit  fld  g_r4                                           ;get real4  fst  l_r8_1                                         ;save as real8 (FPU method)  fstp l_r10                                          ;save as real10  movss xmm0, g_r4                                    ;get real4  cvtss2sd xmm1, xmm0                                 ;convert to real8 (mmx method)  movsD  l_r8_2, xmm1                                 ;save  .if (l_r8_1 == l_r8_2)                              ;is equal, which correct    MessageBoxW(0, "ok #1", "Test #1", 0)              .endif    .if (g_r8 == l_r8_2)                                ;should be equal, but isn´t    MessageBoxW(0, "ok #2", "Test #2", 0)               .endif    .if (g_r8 == l_r8_1)                                ;should be equal, but isn´t    MessageBoxW(0, "ok #3", "Test #3", 0)            .endif    fld g_r10  fld l_r10  fcompp  fnstsw ax                jne @F    MessageBoxW(0, "ok #4", "Test #4", 0)            @@:  invoke ExitProcess, 0  retstart endp  end start`
The first try displays only the first messagebox, because g_r4, g_r8 and g_r10 are initialized to different numbers. The second try shows all boxes, because g_r4, g_r8 and g_r10 are initialized in a way that "up-sizing" from real4 to real8 or real10, creates reals, which compare equal to the initial real. The second initialization process slightly differs from the first one and so do the floats. I want it the second way.

But as already mentioned getting the correct number (418CCCCDr in this case) is cumbersome. So i´m looking for a way of letting ASMC do this work, because it already does these calculations internally anyway.

The problem is about precision, this is true. Currently ASMC initializes a real with it´s default precision (a real4 with real4 precision, a real8 with real8 precision, ...). In my case (17.6 = 3 digits of precision, which is in real4 range) a real8 or real10 should be initialized with real4 precision (following the precision of the initializing number and not the precision of the floating point type). I hope, i could explain this clear enough now.

JK

#### mineiro

• Member
• Posts: 810
##### Re: Large integers and floats
« Reply #64 on: October 02, 2021, 12:57:25 AM »
I feel that I'm flying in this topic, if this is truth, please, ignore this post.
Code: [Select]
`mov eax,1759999942         ;17.59999942         ;418ccccc uasmmov ecx,1mov edx,100000000           ;precision: 1/100000000 or 0,00000001cvtsi2ss xmm0,eaxcvtsi2ss xmm1,ecxcvtsi2ss xmm2,edxdivss xmm1,xmm2mulss xmm0,xmm1             ;1759999942 * 0,00000001movd esi,xmm0               ;esi = 418ccccdhmov eax,176              ;17.6mov ecx,1mov edx,10              ;precision: 1/10 or 0,1cvtsi2ss xmm0,eaxcvtsi2ss xmm1,ecxcvtsi2ss xmm2,edxdivss xmm1,xmm2mulss xmm0,xmm1             ;176 * 0,1movd edi,xmm0               ;edi = 418ccccdhxor esi,edi                 ;cmpjnz not_equalequal:nopnot_equal:nop`
I'd rather be this ambulant metamorphosis than to have that old opinion about everything

#### raymond

• Member
• Posts: 271
##### Re: Large integers and floats
« Reply #65 on: October 02, 2021, 03:33:57 AM »
My apology if this may not sound the way which some people would like, but I think that this whole discussion has been totally useless.

Comparisons are made for many totally different reasons, and the procedures can be totally different from one another. The  required logic simply cannot be built into a one-size-fits-all "macro". If you need to compare two numerical values, state the specific critical reasons for its need, and then the various coding possibilities can be discussed.
Whenever you assume something, you risk being wrong half the time.
http://www.ray.masmcode.com/

#### jj2007

• Member
• Posts: 11768
• Assembler is fun ;-)
##### Re: Large integers and floats
« Reply #66 on: October 02, 2021, 10:46:01 AM »
@JK I understand your desire, and it is somewhat true that you can initialise data in three sizes that afterwards result equal. However, the trick with the fld, fst, fstp sequence works only in one direction:

fld Real4 -> fst Real8 ->fstp Real10
Code: [Select]
`Loaded 4...10SevenTeenPointSix10     17.60000038146972656SevenTeenPointSix8      17.60000038146973SevenTeenPointSix4      17.60000Real4 vs Real8:R4=R8 at top precisionR4=R8 at high precisionR4=R8 at medium precision`
Great, isn't it? They are equal
However, the Real4 and Real8 numbers don't look that nice... and indeed, if you choose the other sequence, it quickly becomes apparent that there is no equality with the precise numbers:

fld Real10 -> fst Real8 ->fstp Real4
Code: [Select]
`Loaded 10...4SevenTeenPointSix10     17.60000000000000000SevenTeenPointSix8      17.60000000000000SevenTeenPointSix4      17.60000Real4 vs Real8:R4 greater than R8 at top precisionR4 greater than R8 at high precisionR4=R8 at medium precision`
So what you are asking for is initialising data with the exact 17.6 value for a REAL4 but a crippled version of that number for the higher precision numbers. It's possible but I don't know how useful that would be...

IMHO the better approach is to use the exact numbers for each data size, and then compare two data items taking account of the different precisions, see "R4=R8 at medium precision" above. This is what you need in practice. If you have an amount of 100.00 US\$, and compare it to another item that is 100.00000001 US\$ or 99.99999 US\$, then you want to see "they are equal", right?

#### JK

• Member
• Posts: 156
##### Re: Large integers and floats
« Reply #67 on: October 02, 2021, 10:49:10 PM »
I always appreciate all the help ´m getting in this forum, but even at the risk of appearing arrogant or ungrateful:
My question was not about WHY i would do something or IF i should do something, it was about HOW i could do something.

In my opening post i stated that i already know about the problems of comparing floats. Nidud gave a working (yet a bit unsatisfying, because of the necessary calculations) answer and added a link, which explains the problems of comparing floats in depth.

So my next (ASMC specific) question was, if there was a more elegant way of initializing floats the way i wanted it - it turned out, that there wasn´t. So for now i have two ways to go: pre-calculate the value and use real hex notation (thanks mineiro !), or initialize a temp value, load it in to the FPU or a mmx register and save it "up-sized", which seems easier for me.

The rest of the discussion was indeed a bit useless and apologize for it.

JK

#### raymond

• Member
• Posts: 271
##### Re: Large integers and floats
« Reply #68 on: October 03, 2021, 10:59:41 AM »
Whenever we discuss any topic on this forum, we should always keep in mind that "newbies" with very little knowledge of the subject may be lurking and misinterpret some of the statements.

Floating point data is handled 'behind the scene' by most (if not all) other programming languages; when compared, they are generally considered as absolute values in the same way that integer data is considered. This is where newcomers to assembly (or even to the subject itself) must be educated to think differently.

For example, if you have a result which must be compared to a target, you should define the difference delta between the two of them which must be exceeded if they are to be considered as equal or not.

A typical code (primarily for newbies) could be as follows, assuming the value to be compared is already in st(0)

Code: [Select]
`fld st(0)    ;make copy of resultfld targetfsub st(0),st(1)  ;get their differencefabs         ;make sure it's positive for next comparisonfld delta    ;load allowable differencefcomip st(0),st(1) ;check if difference from target is large enough to be considered as non-equalfstp st(0)   ;clean fpu leaving original result.if CARRY?   ;the difference with the target would be larger than the specified delta    ;code for non-equality (and possibly check for errors if deemed a possibility).else        ;"result" can be considered equal to "target"    ;code for equality.endif`
Using JJ"s latest example, you may define the delta as 0.01 as an appropriate value when making comparisons of monetary sums (although it would be somewhat insignificant when the comparison would involve the annual US budget)!!!!
Whenever you assume something, you risk being wrong half the time.
http://www.ray.masmcode.com/

#### nidud

• Member
• Posts: 2307
##### Re: Large integers and floats
« Reply #69 on: October 03, 2021, 09:56:43 PM »

Well, here's how this could be done. It's possible to use the floatformat option X to convert from real16(imm) to real4(hex).

This macro skips the rounding bit (and a few other things) so the output from 17.6 is 418CCCCCr.

r4 macro q

local e, b, m

e = q shr (128-16)
m = q shl 16
m = m shr (128-32+8)
x = e and 0x7FFF
x = x sub 00000000000000000000000000003FFFr
x = x shl 24
x = x or m
x = x shr 1
e = e and 0x8000
e = e shl 16
x = x or e
option floatformat:x
exitm<@SubStr(@CatStr(%x, <r>), 25)>
endm

a = r4(17.6)
%echo @CatStr(<a = >, %a)
a = 40031999980000000000000000000000

option floatformat:f, floatdigits: 4
%echo @CatStr(<a = >, %a)
a = 17.6000

Convert and compare (real4/8/10).
Code: [Select]
`cmpfd proto :real4, :real8 {    cvtsd2ss xmm1,xmm1    comiss xmm0,xmm1    retm<(ZERO?)>    }cmpdf proto :real8, :real4 {    cvtss2sd xmm1,xmm1    comisd xmm0,xmm1    retm<(ZERO?)>    }    .data     g_r4 real4  r4(17.6)     g_r8 real8  r4(17.6)     g_r10 real10 r4(17.6)    .codemain proc    .if cmpfd(g_r4, g_r8)        printf("g_r4 == g_r8: %.04f\n", g_r8)    .endif    .if cmpdf(g_r8, g_r4)        printf("g_r8 == g_r4: %.04f\n", g_r8)    .endif    fld  g_r10    fstp g_r8    .if cmpdf(g_r8, g_r4)        printf("g_r10 == g_r4: %.04f\n", g_r8)    .endif    retmain endp`g_r4 == g_r8: 17.6000
g_r8 == g_r4: 17.6000
g_r10 == g_r4: 17.6000

#### daydreamer

• Member
• Posts: 1813
• green elevator
##### Re: Large integers and floats
« Reply #70 on: October 03, 2021, 10:16:17 PM »
For example, if you have a result which must be compared to a target, you should define the difference delta between the two of them which must be exceeded if they are to be considered as equal or not.

A typical code (primarily for newbies) could be as follows, assuming the value to be compared is already in st(0)

Code: [Select]
`fld st(0)    ;make copy of resultfld targetfsub st(0),st(1)  ;get their differencefabs         ;make sure it's positive for next comparisonfld delta    ;load allowable differencefcomip st(0),st(1) ;check if difference from target is large enough to be considered as non-equalfstp st(0)   ;clean fpu leaving original result.if CARRY?   ;the difference with the target would be larger than the specified delta    ;code for non-equality (and possibly check for errors if deemed a possibility).else        ;"result" can be considered equal to "target"    ;code for equality.endif`
Using JJ"s latest example, you may define the delta as 0.01 as an appropriate value when making comparisons of monetary sums (although it would be somewhat insignificant when the comparison would involve the annual US budget)!!!!
Comparing money,wouldnt it be better to 100* and convert to integers for cents? Before the usual integer Cmp?
Or if only dollars accuracy, round cents to dollars before
Zero = the same in both integers and floats, maybe could take advantage of that in coding?

If you convert to half's before compare?
SIMD fan and macro fan
I am an Invoker
"An Invoker is a mage who specializes in the manipulation of raw and elemental energies."

#### JK

• Member
• Posts: 156
##### Re: Large integers and floats
« Reply #71 on: October 03, 2021, 11:55:53 PM »
Thanks nidud

#### nidud

• Member
• Posts: 2307
##### Re: Large integers and floats
« Reply #72 on: October 04, 2021, 12:13:53 AM »
Here's rounding and support for negative values.

r4 macro q

local e, x, m

e = q shr (128-16)
m = q shl 16
m = m shr (128-32+7)
if ( low64(m) and 1 )
endif
m = m shr 1
x = e and 0x7FFF
x = x sub 0x3FFF
x = x shl 24
x = x or m
x = x shr 1
e = e and 0x8000
e = e shl 16
x = x or e
option floatformat:X
exitm<@SubStr(@CatStr(%x, <r>), 24)>
endm

a = r4(-17.6)
%echo @CatStr(<a = >, %a)
a = C00319999A0000000000000000000000
option floatformat:f, floatdigits: 6
%echo @CatStr(<a = >, %a)
a = -17.600000

« Last Edit: October 04, 2021, 02:21:11 AM by nidud »

#### raymond

• Member
• Posts: 271
##### Re: Large integers and floats
« Reply #73 on: October 04, 2021, 04:44:43 AM »
Comparing money,wouldnt it be better to 100* and convert to integers for cents? Before the usual integer Cmp?
Or if only dollars accuracy, round cents to dollars before
Zero = the same in both integers and floats, maybe could take advantage of that in coding?

If you convert to half's before compare?

As I have mentioned before
Quote
If you need to compare two numerical values, state the specific critical reasons for its need, and then the various coding possibilities can be discussed.
.
Whenever you assume something, you risk being wrong half the time.
http://www.ray.masmcode.com/

#### mineiro

• Member
• Posts: 810
##### Re: Large integers and floats
« Reply #74 on: October 04, 2021, 08:55:49 AM »
Floating point data is handled 'behind the scene' by most (if not all) other programming languages; when compared, they are generally considered as absolute values in the same way that integer data is considered. This is where newcomers to assembly (or even to the subject itself) must be educated to think differently.

Hello sir raymond;
Why?

To me hardware engineers used binary to create fpu unit. Passing current or not in a wire. Digital instead of analogic. Integer numbers.
They do not recreated the wheel, probably used real4 hardware and expand that to real8, ... .
Internally, radix 10 being used we can't express all numbers. An example is 1.0 that will be: 1/2 + 1/4 + 1/8 + ..., 0,5+0,25+0,125+0,0625+ ... = 0,9375. So, in pratice 1.0 will never be reached, only 0,99... . Using integer we reach 1. It's necessary round up in this case or a lookup table.
But again, if it's necessary think in fractional part as I do now, the result will be stored in integer binary form, signal, mantissa, number, a form/encoding.
If I think in integer way, I can have byte,word,dword,qword. Any of these values can fit in a byte range. Like real4,real8,... can fit in real4 .

Well, I understood arithmetic encoding. If I have a number with 99 zeros and 1 one; this number can fit in Claude Shannon entropy formula:
99/100 * log2 (99/100) + 1/100 * log2 (1/100) == 0,080793136 bits.
So, to represent each symbol in that message (99 zeros and 1 one) its necessary 0,080793136 bits.
Final message, whole number, will have a size of 0,080793136*100 digits == 8,0793136 bits (fractional) or 9 (integer) bits to be represented. And fractional part isn't above 5 to be round up. I can't use 8 bits because will give data loss; 8,07 bits should be rounded up to 9 bits to be represented without data loss.

This is the reason I'm asking why? Final encoding/form will be stored in bits.
I'd rather be this ambulant metamorphosis than to have that old opinion about everything