### Author Topic: Real4 to Real8 conversion problem  (Read 1365 times)

#### jj2007

• Member
• Posts: 8085
• Assembler is fun ;-)
##### Real4 to Real8 conversion problem
« on: July 24, 2017, 08:38:42 PM »
This function expects a REAL4 on the stack, and a pointer to a destination REAL8:
Code: [Select]
`R4ToR8 proc uses esi ecx rx4:REAL4, pR8  mov esi, rx4 ; load real4 into one register  mov ecx, esi  shr esi, 23  and esi, 11111111b ; 8 bits expo  add esi, 1023-127 ; new bias  and ecx, 11111111111111111111111b ; 23 bits mantissa  if 0 shl ecx, 1 ; seems to "improve" the results but...  endif  shl esi, 20 ; 52-32  or esi, ecx ; merge expo and mantissa  test byte ptr rx4[3], 128 ; is passed REAL4 negative?  .if Sign? or esi, 10000000000000000000000000000000b ; make REAL8 negative, too  .endif  mov edx, pR8  and dword ptr [edx], 0 ; zero out the less significant bits of the mantissa  mov dword ptr [edx+4], esi  retR4ToR8 endp`
Looks simple enough, but this loop...
Code: [Select]
`  For_ fct=-1.2 To 1.2 Step 0.1 invoke R4ToR8, fct, addr r8new Print Str\$("R4: %5f", fct) Print At(16, Locate(y)) Str\$(" R8: %8f\n", r8new)  Next `
... produces the following:
Code: [Select]
`R4: -1.2000      R8: -1.6000004R4: -1.1000      R8: -1.8000002R4: -1.0000      R8: -1.0000000R4: -0.90000     R8: -0.69999981R4: -0.80000     R8: -0.89999962R4: -0.70000     R8: -1.1999989R4: -0.60000     R8: -1.5999985R4: -0.50000     R8: -1.9999971R4: -0.40000     R8: -0.44999933R4: -0.30000     R8: -0.39999938R4: -0.20000     R8: -0.22499943R4: -0.100000    R8: -1.7999907R4: 7.3016e-08   R8: 1.0728837e-07R4: 0.10000      R8: 1.8000097R4: 0.20000      R8: 0.22500062R4: 0.30000      R8: 0.40000057R4: 0.40000      R8: 0.45000052R4: 0.50000      R8: 0.50000048R4: 0.60000      R8: 1.6000013R4: 0.70000      R8: 1.2000017R4: 0.80000      R8: 0.90000105R4: 0.90000      R8: 0.70000124R4: 1.0000       R8: 1.0000010R4: 1.1000       R8: 1.8000011R4: 1.2000       R8: 1.6000013`
The results are partly wrong. Anybody to spot the error in my code or in my logic? I am pretty bad at these things, so bear with me if I did something stupid.

And of course, I know that fld R4, fstp R8 is shorter and faster. This is intended to convert between REAL10 and REAL16 - if it is possible. Full MB source is attached.

#### aw27

• Member
• Posts: 1087
• Let's Make ASM Great Again!
##### Re: Real4 to Real8 conversion problem
« Reply #1 on: July 24, 2017, 09:04:37 PM »
I did not run your code but it appears that you forgot that real8 is a qword.

shl esi, 20      ; 52-32

This looks wrong.

#### jj2007

• Member
• Posts: 8085
• Assembler is fun ;-)
##### Re: Real4 to Real8 conversion problem
« Reply #2 on: July 24, 2017, 09:46:58 PM »
The shl puts the expo into its position, and that part works.
No, the issue is here:
Add esi, 1023-127
Shr ecx, 3
And ecx, ...
Mov eax, rx4
Shl eax, 29
Mov (edx), eax

Wotks! Internet down here, posting from a mobile. Horrible

#### mabdelouahab

• Member
• Posts: 362
##### Re: Real4 to Real8 conversion problem
« Reply #3 on: July 24, 2017, 10:50:42 PM »
I think the problem is not in the R4ToR8 proc, Maybe the problem is in For_ or Print with r4 , Try to out it as binary and see

#### aw27

• Member
• Posts: 1087
• Let's Make ASM Great Again!
##### Re: Real4 to Real8 conversion problem
« Reply #4 on: July 24, 2017, 11:13:35 PM »
Code: [Select]
`R4ToR8 proc uses ebx esi ecx rx4:REAL4, pR8  mov esi, rx4 ; load real4 into one register  mov ecx, esi    shr esi, 23  and esi, 11111111b ; 8 bits expo  add esi, 1023-127 ; new bias  and ecx, 11111111111111111111111b ; 23 bits mantissa  if 0 shl ecx, 1 ; seems to "improve" the results but...  endif  shl esi, 20 ; 52-32  mov ebx, ecx  shr ebx, 3  or esi, ebx;  and ecx, 111b no need  shl ecx, 29    test byte ptr rx4[3], 128 ; is passed REAL4 negative?  .if Sign? or esi, 10000000000000000000000000000000b ; make REAL8 negative, too  .endif  mov edx, pR8  mov dword ptr [edx], ecx ; fixed on 28th August (previously was "and dword ptr [edx], ecx")  mov dword ptr [edx+4], esi  retR4ToR8 endp`
This works.
« Last Edit: August 30, 2017, 01:55:26 AM by aw27 »

#### jj2007

• Member
• Posts: 8085
• Assembler is fun ;-)
##### Re: Real4 to Real8 conversion problem
« Reply #5 on: July 25, 2017, 10:09:47 AM »
Internet is back

Here is the correct version with the changes announced above:
Code: [Select]
`R4ToR8 proc uses esi ecx rx4:REAL4, pR8  mov esi, rx4 ; load real4 into one register  mov ecx, esi  shr esi, 23  and esi, 11111111b ; 8 bits expo  add esi, 1023-127 ; new bias  mov eax, ecx ; save last 3 bits  shr ecx, 3 ; bingo!  and ecx, 11111111111111111111111b ; 23 bits mantissa  shl esi, 20 ; 52-32  or esi, ecx ; merge expo and mantissa  test byte ptr rx4[3], 128 ; is passed REAL4 negative?  .if Sign? or esi, 10000000000000000000000000000000b ; make REAL8 negative, too  .endif  mov edx, pR8  mov eax, rx4  shl eax, 32-3  mov dword ptr [edx], eax ; put the less significant bits of the mantissa  mov dword ptr [edx+4], esi  retR4ToR8 endp`
Project attached, including José's almost correct version. The exe shows the difference between the original and the converted number, which should be zero, of course. Start from a DOS prompt, I forgot to put an inkey

#### aw27

• Member
• Posts: 1087
• Let's Make ASM Great Again!
##### Re: Real4 to Real8 conversion problem
« Reply #6 on: July 25, 2017, 02:24:15 PM »
Quote
Project attached, including José's almost correct version.

You are so funny, I can't spot any error in my code but in yours

1)
mov eax, ecx   ; save last 3 bits
You save but don't reuse the saved value.
2)
shr ecx, 3      ; bingo!
and ecx, 11111111111111111111111b   ; 23 bits mantissa

You use a 23-bit bitmask after you shift right to keep only 20 bits.

#### jj2007

• Member
• Posts: 8085
• Assembler is fun ;-)
##### Re: Real4 to Real8 conversion problem
« Reply #7 on: July 25, 2017, 07:59:31 PM »
Thank you, José - you are right, the mov eax, ecx was redundant. Here is the final version:

R4ToR8 proc rx4:REAL4, pR8              ; version jj
mov edx, rx4                          ; load real4 into one register
mov eax, edx                          ; make a copy
shr edx, 23
movzx edx, dl                         ; 8 bits expo
add edx, 1023-127                     ; new bias
shr eax, 3                            ; bingo!
and eax, 11111111111111111111111b     ; 23 bits mantissa
shl edx, 20                           ; 52-32
or edx, eax                           ; merge expo and mantissa
test byte ptr rx4[3], 128             ; is passed REAL4 negative?
.if Sign?
bts edx, 31                     ; make REAL8 negative, too
.endif
push edx
mov eax, pR8
mov edx, rx4
shl edx, 32-3
mov dword ptr [eax], edx              ; put the less significant bits of the mantissa
pop dword ptr [eax+4]                 ; expo and most significant bits of mantissa
ret
R4ToR8 endp

And here is the relevant output:
Code: [Select]
`-- R4ToR8 jj --R4: -123456.789  R8: -123456.789  diff: 0.0     10100000000000000000000000000000.11000000111111100010010000001100R4: -111111.789  R8: -111111.789  diff: 0.0     10100000000000000000000000000000.11000000111110110010000001111100R4: -98766.7891  R8: -98766.7891  diff: 0.0     10100000000000000000000000000000.11000000111110000001110011101100R4: -86421.7891  R8: -86421.7891  diff: 0.0     10100000000000000000000000000000.11000000111101010001100101011100R4: -74076.7891  R8: -74076.7891  diff: 0.0     10100000000000000000000000000000.11000000111100100001010111001100R4: -61731.7891  R8: -61731.7891  diff: 0.0     01000000000000000000000000000000.11000000111011100010010001111001R4: -49386.7891  R8: -49386.7891  diff: 0.0     01000000000000000000000000000000.11000000111010000001110101011001R4: -37041.7891  R8: -37041.7891  diff: 0.0     01000000000000000000000000000000.11000000111000100001011000111001R4: -24696.7891  R8: -24696.7891  diff: 0.0     10000000000000000000000000000000.11000000110110000001111000110010R4: -12351.7891  R8: -12351.7891  diff: 0.0     00000000000000000000000000000000.11000000110010000001111111100101R4: -6.78906250  R8: -6.78906250  diff: 0.0     00000000000000000000000000000000.11000000000110110010100000000000R4: 12338.2109   R8: 12338.2109   diff: 0.0     00000000000000000000000000000000.01000000110010000001100100011011R4: 24683.2109   R8: 24683.2109   diff: 0.0     10000000000000000000000000000000.01000000110110000001101011001101R4: 37028.2109   R8: 37028.2109   diff: 0.0     11000000000000000000000000000000.01000000111000100001010010000110R4: 49373.2109   R8: 49373.2109   diff: 0.0     11000000000000000000000000000000.01000000111010000001101110100110-- R4ToR8 aw27 --R4: -123456.789  R8: -123456.781  diff: 0.0078  10000000000000000000000000000000.11000000111111100010010000001100R4: -111111.789  R8: -111111.781  diff: 0.0078  10000000000000000000000000000000.11000000111110110010000001111100R4: -98766.7891  R8: -98766.7812  diff: 0.0078  10000000000000000000000000000000.11000000111110000001110011101100R4: -86421.7891  R8: -86421.7812  diff: 0.0078  10000000000000000000000000000000.11000000111101010001100101011100R4: -74076.7891  R8: -74076.7812  diff: 0.0078  10000000000000000000000000000000.11000000111100100001010111001100R4: -61731.7891  R8: -61731.7812  diff: 0.0078  00000000000000000000000000000000.11000000111011100010010001111001R4: -49386.7891  R8: -49386.7812  diff: 0.0078  00000000000000000000000000000000.11000000111010000001110101011001R4: -37041.7891  R8: -37041.7812  diff: 0.0078  00000000000000000000000000000000.11000000111000100001011000111001R4: -24696.7891  R8: -24696.7812  diff: 0.0078  00000000000000000000000000000000.11000000110110000001111000110010R4: -12351.7891  R8: -12351.7891  diff: 0.0     00000000000000000000000000000000.11000000110010000001111111100101R4: -6.78906250  R8: -6.78906250  diff: 0.0     00000000000000000000000000000000.11000000000110110010100000000000R4: 12338.2109   R8: 12338.2109   diff: 0.0     00000000000000000000000000000000.01000000110010000001100100011011R4: 24683.2109   R8: 24683.2031   diff: -0.0078 00000000000000000000000000000000.01000000110110000001101011001101R4: 37028.2109   R8: 37028.1875   diff: -0.023  00000000000000000000000000000000.01000000111000100001010010000110R4: 49373.2109   R8: 49373.1875   diff: -0.023  00000000000000000000000000000000.0100000011101000000110111010011062      bytes for R4ToR872      bytes for R4ToR8aw`
Project attached. As before, "diff" is the difference between the Real4 and the converted Real8, and it should be zero, of course. This time there is an Inkey at the end, so you can start it directly from the archive (old versions included for comparison).

#### Adamanteus

• Member
• Posts: 189
##### Re: Real4 to Real8 conversion problem
« Reply #8 on: July 26, 2017, 12:24:12 AM »
Demormilised values looks like not processed, so why not use coprocessor for it :
Code: (asm) [Select]
`R4ToR8 proc rx4:REAL4, pR8  fld rx4 mov ebx, pr8 fstp dword ptr [ebx]  retR4ToR8 endp`

#### jj2007

• Member
• Posts: 8085
• Assembler is fun ;-)
##### Re: Real4 to Real8 conversion problem
« Reply #9 on: July 26, 2017, 12:34:40 AM »
why not use coprocessor for it

And of course, I know that fld R4, fstp R8 is shorter and faster.

#### jj2007

• Member
• Posts: 8085
• Assembler is fun ;-)
##### Re: Real4 to Real8 conversion problem
« Reply #10 on: July 31, 2017, 09:08:11 AM »
In the meantime, I have polished the routines a little bit, and made them fit for conversions between REAL16 and other numbers. The syntax is hopefully simple enough - FpuPush somequad and Quad(somenumber):

include \masm32\MasmBasic\MasmBasic.inc
SetGlobals REAL16 quadNumber
SetGlobals MyFloat:REAL4=1234567890.1234567890
SetGlobals MyDouble:REAL8=1234567890.1234567890
SetGlobals MyReal10:REAL10=1234567890.1234567890
Init quad
MovVal quadNumber, "1234567890.123456789012345678901234567890"        ; convert string to REAL16
PrintLine "Real16=  ", Tb\$, Quad\$(quadNumber)         ; print a REAL16 at full 33 digit precision
FpuPush quadNumber                                    ; convert REAL16 and push it on the FPU
fstp MyReal10                                         ; save as REAL10
PrintLine Str\$("Real10=\t\t%Jf", MyReal10)            ; and print it
PrintLine "Real10=  ", Tb\$, Quad\$(Quad(MyReal10))     ; convert REAL10 to REAL16 and print it
PrintLine "Real8=   ", Tb\$, Quad\$(Quad(MyDouble))     ; convert REAL8 to REAL16 and print it
movups quadNumber, Quad(MyFloat)                      ; convert REAL4 to REAL16
PrintLine "Real4=   ", Tb\$, Quad\$(quadNumber)         ; and print it
Inkey "ok?"
EndOfCode

For the time being, building this code requires the 30 July beta (and running it needs two GCC DLLs).

Output:
Code: [Select]
`Real16=         1.23456789012345678901234567890123e+09Real10=         1234567890.123456789Real10=         1.23456789012345678894780576229095e+09Real8=          1.23456789012345671653747558593750e+09Real4=          1.23456793600000000000000000000000e+09`

#### jj2007

• Member
• Posts: 8085
• Assembler is fun ;-)
##### Re: Real4 to Real8 conversion problem
« Reply #11 on: August 30, 2017, 03:31:56 AM »
José has posted a new version of his code, and it works now
Code: [Select]
`-- R4ToR8 jj --423 ms-- R4ToR8 aw27 --405 ms-- R4ToR8 jj --R4: -123456.789      R8: -123456.789       diff: 0.0R4: -111111.789      R8: -111111.789       diff: 0.0R4: -98766.7891      R8: -98766.7891       diff: 0.0R4: -86421.7891      R8: -86421.7891       diff: 0.0R4: -74076.7891      R8: -74076.7891       diff: 0.0R4: -61731.7891      R8: -61731.7891       diff: 0.0R4: -49386.7891      R8: -49386.7891       diff: 0.0R4: -37041.7891      R8: -37041.7891       diff: 0.0R4: -24696.7891      R8: -24696.7891       diff: 0.0R4: -12351.7891      R8: -12351.7891       diff: 0.0R4: -6.78906250      R8: -6.78906250       diff: 0.0R4: 12338.2109       R8: 12338.2109        diff: 0.0R4: 24683.2109       R8: 24683.2109        diff: 0.0R4: 37028.2109       R8: 37028.2109        diff: 0.0R4: 49373.2109       R8: 49373.2109        diff: 0.0-- R4ToR8 aw27 --R4: -123456.789      R8: -123456.789       diff: 0.0R4: -111111.789      R8: -111111.789       diff: 0.0R4: -98766.7891      R8: -98766.7891       diff: 0.0R4: -86421.7891      R8: -86421.7891       diff: 0.0R4: -74076.7891      R8: -74076.7891       diff: 0.0R4: -61731.7891      R8: -61731.7891       diff: 0.0R4: -49386.7891      R8: -49386.7891       diff: 0.0R4: -37041.7891      R8: -37041.7891       diff: 0.0R4: -24696.7891      R8: -24696.7891       diff: 0.0R4: -12351.7891      R8: -12351.7891       diff: 0.0R4: -6.78906250      R8: -6.78906250       diff: 0.0R4: 12338.2109       R8: 12338.2109        diff: 0.0R4: 24683.2109       R8: 24683.2109        diff: 0.0R4: 37028.2109       R8: 37028.2109        diff: 0.0R4: 49373.2109       R8: 49373.2109        diff: 0.073      bytes for R4ToR8jj72      bytes for R4ToR8aw`
Two projects attached, #1 as shown above, #2 includes timings of the MasmBasic RealX->Real16 conversion macro, Quad().
« Last Edit: August 30, 2017, 09:57:39 AM by jj2007 »