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           ;?.6
mov ecx,10
cvtsi2ss xmm0,eax   ;cvtsi2sd
cvtsi2ss xmm1,ecx   ;cvtsi2sd
divss xmm0,xmm1     ;divsd , 0.6

;integer part
mov eax,1           ;17 = 1*10^1 + 7*10^0
mov ecx,10          ;1,10,100,1000,...
cvtsi2ss xmm1,eax
cvtsi2ss xmm2,ecx
mulss xmm1,xmm2
mov eax,7
cvtsi2ss xmm2,eax
addss xmm1,xmm2

;integer part xmm1 + fractional part xmm0
addss xmm0,xmm1     ;17.0 + 0.6
movd 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 ;-)
    • MasmBasic
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.600000381469726560
SevenTeenPointSix8 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:ON

include windows.inc
includelib kernel32.lib
includelib user32.lib

.data
;*************************************************************************************
; 1st try
;*************************************************************************************
g_r4  real4  17.6
g_r8  real8  17.6
g_r10 real10 17.6


;*************************************************************************************
; 2nd try
;*************************************************************************************
;g_r4  real4  418CCCCDr
;g_r8  real8  418CCCCDr
;g_r10 real10 418CCCCDr


.code


start proc
;***************************************************************************
; main
;***************************************************************************
local l_r4 :real4
local l_r8_1 :real8
local l_r8_2 :real8
local 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
  ret

start 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 uasm
mov ecx,1
mov edx,100000000           ;precision: 1/100000000 or 0,00000001
cvtsi2ss xmm0,eax
cvtsi2ss xmm1,ecx
cvtsi2ss xmm2,edx
divss xmm1,xmm2
mulss xmm0,xmm1             ;1759999942 * 0,00000001
movd esi,xmm0               ;esi = 418ccccdh

mov eax,176              ;17.6
mov ecx,1
mov edx,10              ;precision: 1/10 or 0,1
cvtsi2ss xmm0,eax
cvtsi2ss xmm1,ecx
cvtsi2ss xmm2,edx
divss xmm1,xmm2
mulss xmm0,xmm1             ;176 * 0,1
movd edi,xmm0               ;edi = 418ccccdh

xor esi,edi                 ;cmp
jnz not_equal
equal:
nop
not_equal:
nop
I'd rather be this ambulant metamorphosis than to have that old opinion about everything

raymond

  • Member
  • ***
  • Posts: 271
    • Raymond's page
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 ;-)
    • MasmBasic
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...10
SevenTeenPointSix10     17.60000038146972656
SevenTeenPointSix8      17.60000038146973
SevenTeenPointSix4      17.60000

Real4 vs Real8:
R4=R8 at top precision
R4=R8 at high precision
R4=R8 at medium precision

Great, isn't it? They are equal :thumbsup:
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...4
SevenTeenPointSix10     17.60000000000000000
SevenTeenPointSix8      17.60000000000000
SevenTeenPointSix4      17.60000

Real4 vs Real8:
R4 greater than R8 at top precision
R4 greater than R8 at high precision
R4=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
    • Raymond's page
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 result
fld target
fsub st(0),st(1)  ;get their difference
fabs         ;make sure it's positive for next comparison
fld delta    ;load allowable difference
fcomip st(0),st(1) ;check if difference from target is large enough to be considered as non-equal
fstp 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)!!!! :skrewy:
Whenever you assume something, you risk being wrong half the time.
http://www.ray.masmcode.com/

nidud

  • Member
  • *****
  • Posts: 2307
    • https://github.com/nidud/asmc
Re: Large integers and floats
« Reply #69 on: October 03, 2021, 09:56:43 PM »
 :biggrin:

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 add 0000000000000000000000000000007Fr
    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)

    .code

main 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
    ret
main 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 result
fld target
fsub st(0),st(1)  ;get their difference
fabs         ;make sure it's positive for next comparison
fld delta    ;load allowable difference
fcomip st(0),st(1) ;check if difference from target is large enough to be considered as non-equal
fstp 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)!!!! :skrewy:
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  :thumbsup:

nidud

  • Member
  • *****
  • Posts: 2307
    • https://github.com/nidud/asmc
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 )
    m = m add 1
endif
    m = m shr 1
    x = e and 0x7FFF
    x = x sub 0x3FFF
    x = x add 0x007F
    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
    • Raymond's page
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