(nearly) ieee 754 floating point single precisition

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Message
Author
einstein1969
Expert
Posts: 960
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: (nearly) ieee 754 floating point single precisition

#31 Post by einstein1969 » 04 Jun 2014 12:13

Thanks penpen!

I have tested the Sin(x) of previus post for see the error.

The result on single test is VERY GOOD! :D

Code: Select all

@echo  off

rem sin(x)

call :sin "1.73"

goto :eof


:sin %1=x radiants

set x=%~1

rem calculate SIN(x) ~ x * ( 1 - x^2 * (1/6 - x^2 * (1/120 - x^2 * (1/5040 - x^2 * (1/362880 - x^2 * 1/39916800 )))))

rem calculate x^2
call :floatTestMul2 "%x%" "%x%"  "xx"

call :floatTestMul2 "%xx%" "2.5052108385441718775052108385442e-8" "sinp"

call :floatTestSub2 "2.7557319223985890652557319223986e-6" "%sinp%" "sinp2"

call :floatTestMul2 "%xx%" "%sinp2%" "sinp3"

call :floatTestSub2 "1.984126984126984126984126984127e-4" "%sinp3%" "sinp4"

call :floatTestMul2 "%xx%" "%sinp4%" "sinp5"

call :floatTestSub2 "0.00833333333333333" "%sinp5%" "sinp6"

call :floatTestMul2 "%xx%" "%sinp6%" "sinp7"

call :floatTestSub2 "0.16666666666666666" "%sinp7%" "sinp8"

call :floatTestMul2 "%xx%" "%sinp8%" "sinp9"

call :floatTestSub2 "1" "%sinp9%" "sinp10"

call :floatTestMul2 "%x%" "%sinp10%" "sin"

echo Sin(%x%)=%sin%

pause

goto :eof

:: functions add for return a value in variable

:floatTestMul2
::   %~1 float string multiplicand1
::   %~2 float string multiplicand2
   setlocal
   set "value1=%~1"
   set "value2=%~2"
 
   call :str2float "%value1%" "float1"
   call :str2float "%value2%" "float2"
   call :floatMul "%float1%" "%float2%" "float3"

   call :intToHex "hex1" "%float1%"
   call :intToHex "hex2" "%float2%"
   call :intToHex "hex3" "%float3%"


   call :float2str "%float3%" "string1"

   rem echo %value1% * %value2% = %float1% * %float2% == %hex1% * %hex2% == %hex3% == %float3% == %string1%

   endlocal & set "%~3=%string1%"
   goto :eof

:floatTestSub2
::   %~1 float string minuend
::   %~2 float string subtrahend
::       else echo hex value if undefined
   setlocal
   set "value1=%~1"
   set "value2=%~2"

   call :str2float "%value1%" "float1"
   call :str2float "%value2%" "float2"
   call :floatSub "%float1%" "%float2%" "float3"

   call :intToHex "hex1" "%float1%"
   call :intToHex "hex2" "%float2%"
   call :intToHex "hex3" "%float3%"


   call :float2str "%float3%" "string1"

   rem echo %value1% - %value2% = %float1% - %float2% == %hex1% - %hex2% == %hex3% == %float3% == %string1%

   endlocal & set "%~3=%string1%"
   goto :eof


result:

Code: Select all

Sin(1.73)=0.9873535


the windows calculator return:
0,98735383970071645108567767622206
0.9873535

I'm very happy :D

You have done a very good work! 8)

EDIT: We have the SIN(x)!!!!

einstein1969

einstein1969
Expert
Posts: 960
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: (nearly) ieee 754 floating point single precisition

#32 Post by einstein1969 » 04 Jun 2014 14:48

Hi penpen,

There is another correction to do:

If the second operand %2 of FLOATSUB is 0 the inv is calculated:

Code: Select all

   set /A "inv=(1<<31)^%~2"


result:

Code: Select all

inv = -2147483648


and when this is assigned at variables get the error like "The numbers are limitated at 32bit precision etc..."

einstein1969

penpen
Expert
Posts: 2009
Joined: 23 Jun 2013 06:15
Location: Germany

Re: (nearly) ieee 754 floating point single precisition

#33 Post by penpen » 04 Jun 2014 15:27

einstein1969 wrote:We have the SIN(x)!!!!
Nice 8) !

einstein1969 wrote:(...)
when this is assigned at variables get the error like "The numbers are limitated at 32bit precision etc..."
This is one of the reasons, why i have to revise the code:
This not only could happen in the function :floatSub, ...
it could also happen in many other locations; for example near the starts of :floatAdd :floatMul :intToHex, :float2str - but also within these functions there are some locations where this may happen.

So this time you have to wait for the bugfix; sorry for that.
You should avoid using the float representation of "-0", a hotfix for the floatSub function could be this:

Code: Select all

:floatSub
::   %~1 minuend float in int coding
::   %~2 subtrahend float in int coding
::   %~3 resulting float in int coding
   setlocal
   set /A "value=%~2"
   if "%value%" == "0" (
      set "inv=0"
   else (
      set /A "inv=(1<<31)^%~2"
   )
   call :floatAdd "%~1" "%inv%" "inv"
   endlocal & set "%~3=%inv%"
   goto :eof
But i think this time i won't change the source above,
as it doesn't solve the whole problem, and
as the solution of the problem i plan to use seems to work without changing this function.

penpen

einstein1969
Expert
Posts: 960
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: (nearly) ieee 754 floating point single precisition

#34 Post by einstein1969 » 05 Jun 2014 13:08

Hi penpen,

For give a sense at these functions (and test these functions) i have realized a "Plasma" effect.

This is an effect that can show error on visive method. But is nice to look and the work on this is more motivating (at least for me)

Since there is some my workaround on the complete code i don't know if this work.

plasma.cmd (use the ieee754 work):
Image

Code: Select all

@echo off& setlocal EnableDelayedExpansion&Goto :Init_System

:: developed on windows 7 32bit.
:: Use Lucida console 5 for best view

:Main

  call :create_palette

  set /a e=Lenp/2

  for /L %%y in (-30,1,30) do (


    call :str2float "%%y" "fy"

    :: newy=fy/8
    call :floatMul "!fy!" "0x3E000000" newy
    call :float2str "!newy!" "newy"
    call :sin2 "!newy!" siny
    call :str2float "!siny!" "fy"
    call :str2float "!e!" "fe"
    call :floatMul "!fy!" "!fe!" y1
    call :float2str "!y1!" "y1"

    :: get integer part
    set app=!y1:*.=!
    for %%a in (!app!) do set app=!y1:.%%a=!
    if "!app!"=="." set app=0
    set /a iy=e+!app!

    for /L %%x in (-60,1,60) do (

      call :str2float "%%x" "fx"
      call :floatMul "!fx!" "0x3E000000" newx
      call :float2str "!newx!" "newx"
      call :sin2 "!newx!" sinx
      call :str2float "!sinx!" "fx"
      call :str2float "!e!" "fe"
      call :floatMul "!fx!" "!fe!" x1
      call :float2str "!x1!" "x1"

      :: get integer part
      set app=!x1:*.=!
      for %%a in (!app!) do set app=!x1:.%%a=!
      if "!app!"=="." set app=0
      set /a ix=e+!app!
 
      set /a "c=(ix+iy)/2"

      call :plot !c!

    )

   echo(
  )

Goto :EndMain

:sin2 %1=x radiants
   set x=%~1

   if "%x:~0,1%"=="-" (
     set r=-1
     set x=!x:~1!
   ) else (
     set r=1
   )

   rem calculate SIN(x) ~ x * ( 1 - x^2 * (1/6 - x^2 * (1/120 - x^2 * (1/5040 - x^2 * (1/362880 - x^2 * 1/39916800 )))))

   call :str2float "%x%" "fx"

   :: 0x40490FDB=3.14159265....
   call :floatSub "%fx%" "0x40490FDB" "tx"

   if !tx! gtr 0 set /A fx=tx, r=-r

   call :floatMul "%fx%"       "%fx%"       "fxx"
   call :floatMul "%fxx%"      "0x32D7322B" "fsinp"
   call :floatSub "0x3638EF1D" "%fsinp%"    "fsinp2"
   call :floatMul "%fxx%"      "%fsinp2%"   "fsinp3"
   call :floatSub "0x39500D01" "%fsinp3%"   "fsinp4"
   call :floatMul "%fxx%"      "%fsinp4%"   "fsinp5"
   call :floatSub "0x3C088889" "%fsinp5%"   "fsinp6"
   call :floatMul "%fxx%"      "%fsinp6%"   "fsinp7"
   call :floatSub "0x3E2AAAAB" "%fsinp7%"   "fsinp8"
   call :floatMul "%fxx%"      "%fsinp8%"   "fsinp9"
   call :floatSub "0x3F800000" "%fsinp9%"   "fsinp10"
   call :floatMul "%fx%"       "%fsinp10%"  "fsin"

   if !r! lss 0 set /A "fsin=(1<<31)^fsin"

   call :float2str "%fsin%" "sin"

endlocal & set "%~2=%sin%"

goto :eof


:plot %1

 call :color !p[%1]:~0,2! !p[%1]:~-1!

goto :eof


::manual palette
:create_palette %1

  set p=0
  For %%p in (04 4C cE EA A2 21 15 50) do (
 
    set "p[!p!]=%%p°" & set /a p+=1
    set "p[!p!]=%%p±" & set /a p+=1
    set "p[!p!]=%%p²" & set /a p+=1
    set "p[!p!]=%%pÛ" & set /a p+=1

  )

  set /a p-=1
  set Lenp=!p!

goto :eof

Goto :EndMain

:: ( Begin Color Function

:color

    (echo %~2\..\'
    ) > $$$.color.txt && findstr /a:%~1 /f:$$$.color.txt "."

    Shift
    Shift

    If ""=="%~1" Goto :Eof

   goto :color

:: ) End color Fuction


:Init_system

  for /F "tokens=1,2 delims=#" %%a in ('"prompt #$H#$E# & echo on & for %%b in (1) do rem"') do (
  set "DEL=%%a")
 
  <nul set /p ".=%DEL%%DEL%%DEL%%DEL%%DEL%%DEL%" > "'"

Goto :Main

:EndMain
  :: Clearing all garbage
  del '
Goto :Eof


EDIT:
This use the code of ieee 754. On first post. Must merge.

Than the other change is the FloatSub.

This is my patch:

Code: Select all

:floatSub
::   %~1 minuend float in int coding
::   %~2 subtrahend float in int coding
::   %~3 resulting float in int coding
   setlocal

   rem echo sub=%1 %2

   rem my temp patch
   if "%~2"=="0" endlocal & set "%~3=%~1" & goto :eof

   set /A "inv=(1<<31)^%~2"

   rem echo inv = %inv%

   call :floatAdd "%~1" "%inv%" "inv"
   endlocal & set "%~3=%inv%"
   goto :eof


or can use the bugfix of penpen. But I have not tested:

Code: Select all

:floatSub
::   %~1 minuend float in int coding
::   %~2 subtrahend float in int coding
::   %~3 resulting float in int coding
   setlocal
   set /A "value=%~2"
   if "%value%" == "0" (
      set "inv=0"
   else (
      set /A "inv=(1<<31)^%~2"
   )
   call :floatAdd "%~1" "%inv%" "inv"
   endlocal & set "%~3=%inv%"
   goto :eof


Sorry for this pieces of code, but this is working progress.

I will post the complete code in the other thread as soon possible.

einstein1969
Last edited by einstein1969 on 05 Jun 2014 19:55, edited 1 time in total.

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

Re: (nearly) ieee 754 floating point single precisition

#35 Post by foxidrive » 05 Jun 2014 18:57

It doesn't work as it is missing code...

penpen
Expert
Posts: 2009
Joined: 23 Jun 2013 06:15
Location: Germany

Re: (nearly) ieee 754 floating point single precisition

#36 Post by penpen » 20 Aug 2014 08:14

I have removed some bugs, converted the functions to macros, and split the source into two files:
- floaty.bat (the test cases; the source is at the bottom of this post)
- loadFloat.bat (that contains the macros)

So if you want to use the float functions in your batch file you only need to call "loadFloat.bat" once
and then just use the macros; make sure the extensions are enabled (default on most systems):

Code: Select all

@echo off
setlocal enableExtensions

:: load all macros, and exit if it has failed for whatever reasons
call "loadFloat.bat"
if errorLevel 1 exit /b 1

:: use the macros (names are similar to the function names)
for %%a in (operand1 operand2 result string) do set "%%~a="

%$str2float% "10" operand1
%$str2float% "4"  operand2

%$floatAdd%  "%operand1%" "%operand2%" result
%$float2str% "%result%" string
echo("10" + "4" = "%string%"

%$floatSub%  "%operand1%" "%operand2%" result
%$float2str% "%result%" string
echo("10" - "4" = "%string%"

%$floatMul%  "%operand1%" "%operand2%" result
%$float2str% "%result%" string
echo("10" * "4" = "%string%"

endlocal

If you want to read the source (more easily), this "toSource.bat" may help:

Code: Select all

@echo off
setlocal enableExtensions disableDelayedExpansion
call loadFloat.bat

2>nul md "macros"
for %%a in (str2float float2str floatAdd floatSub floatMul intToHex) do (
   (
      set "firstLine=true"
      for /F "tokens=1* delims=:" %%b in ('set $%%~a ^| findstr /N "^"') do (
         if defined firstLine (
            set "firstLine="
            for /F "tokens=1* delims==" %%d in ("%%c") do (
               set line=%%~e
               echo(
            )
         ) else (
            set line=%%~c
         )
         setlocal enableExtensions enableDelayedExpansion
            set "line=!line:%%=%%%%!"
            echo(!line!
         endlocal
      )
   ) > "macros\%%~a.txt"
)

endlocal


This "floaty.bat" contains the test cases (exceeded the maximum number of allowed characters: 60000):

Code: Select all

@echo off
setlocal enableExtensions  disableDelayedExpansion
call loadFloat.bat
if errorLevel 1 (set error=true)
if defined error exit /b 1

call :floatTest ".e                "
call :floatTest ".e3               "
call :floatTest ".2e               "
call :floatTest "1.e               "
call :floatTest "+.e               "
call :floatTest "+1.e              "
call :floatTest "-.e               "
call :floatTest "-1.e              "

call :floatTest "NaN               "
call :floatTest "+NaN              "
call :floatTest "-NaN              "
call :floatTest "+NaN(7FFFFFFF)    "
call :floatTest "-NaN(7FFFFFFF)    "
call :floatTest "+NaN(FFFFFFFF)    "
call :floatTest "-NaN(FFFFFFFF)    "
call :floatTest "+NaN(FF83FFFF)    "
call :floatTest "-NaN(FF83FFFF)    "
call :floatTest "+NaN(FF83FFFF)    "
call :floatTest "-NaN(FF83FFFF)    "

call :floatTest "inf               "
call :floatTest "+inf              "
call :floatTest "-inf              "

call :floatTest "0.0               "
call :floatTest "-0.0              "

call :floatTest "0x01234567        "
call :floatTest "+0x01234567       "
call :floatTest "-0x01234567       "

call :floatTest "1000.0            "
call :floatTest "1000.00006        "

call :floatTest "0.000001          "
call :floatTest "1.4e-45           "
call :floatTest "4.2E-45           "
call :floatTest "1.1754945E-38     "
call :floatTest "5.877472E-39      "
call :floatTest "12.375            "

call :floatTest "0.0001            "
call :floatTest "0.001             "
call :floatTest "0.01              "
call :floatTest "0.1               "
call :floatTest "1                 "
call :floatTest "10                "
call :floatTest "100               "
call :floatTest "1000              "
call :floatTest "10000             "
call :floatTest "100000            "
call :floatTest "1000000           "
call :floatTest "10000000          "

call :floatTest "68.123            "
call :floatTest "1.17549434E-38    "
call :floatTest "5.877472E-39      "

call :floatTest "-1.0e-6           "

call :floatTest "1.763241500000E-38"
call :floatTest "1.14794E-41       "

call :floatTest "1.4E-45           "

call :floatTest "1.0e10            "
call :floatTest "+1.0e+10          "
call :floatTest "- 1.0 e -10       "

echo(
call :floatTest Add "45.0000" "-45.3000"
call :floatTest Add "100" "0.006"
call :floatTest Add "1.4E-45" "1.1754942E-38"
call :floatTest Add "1.4E-45" "1.4E-45"
call :floatTest Add "1" "2"

echo(
call :floatTest Sub "100" "0.006"
call :floatTest Sub "1.4E-45" "1.1754942E-38"
call :floatTest Sub "1.4E-45" "1.4E-45"
call :floatTest Sub "1" "2"

echo(
call :floatTest Mul "100" "0.1"
call :floatTest Mul "100" "0.05"
call :floatTest Mul "100" "0.005"
call :floatTest Mul "1.4E-45" "1"
call :floatTest Mul "2.8E-45" "0.5"

endlocal
endlocal
goto :eof



:floatTest (overloaded)
::
::   one arguments version: converts the string to a float and back, displaying the results
::   %~1 float string
::
::   three arguments version: performs operand1 operator operand2, displays the result in hex/string
::   %~1 float operator in { "add", "sub", "mul" }  (other operators are ignored)
::   %~2 float string operand2
::   %~3 float string operand1
::
   setlocal enableDelayedExpansion
   set "op=%~1"
   set "A=%~2"
   set "B=%~3"

   if %2. == . (
      for %%a in ("float", "hex", "string") do set "%%~a="

      %$str2float% "%~1%"    float
      %$intToHex%  "!float!" hex
      %$float2str% "!float!" string

      echo(!hex! ^<-- "%~1" --^> "!string!"
   ) else (
      for %%a in ("op", "value1", "value2", "float1", "float2", "float3", "hex1", "hex2", "hex3", "string1") do set "%%~a="
      set "op[add]=+"
      set "op[sub]=-"
      set "op[mul]=*"

      set "op=!op[%~1]!"
      set "value1=%~2"
      set "value2=%~3"

      %$str2float% "!value1!" "float1"
      %$str2float% "!value2!" "float2"

      if        /I "%~1" == "add" (
         %$floatAdd% "!float1!" "!float2!" "float3"
      ) else if /I "%~1" == "sub" (
         %$floatSub% "!float1!" "!float2!" "float3"
      ) else if /I "%~1" == "mul" (
         %$floatMul% "!float1!" "!float2!" "float3"
      ) else (
         endlocal
         goto :eof
      )

      %$intToHex% "!float1!" "hex1"
      %$intToHex% "!float2!" "hex2"
      %$intToHex% "!float3!" "hex3"

      %$float2str% "!float3!" "string1"

      echo !value1! !op! !value2! = !float1! !op! !float2! == !hex1! !op! !hex2! == !hex3! == !float3! == !string1!
   )

   endlocal
   goto :eof

penpen

einstein1969
Expert
Posts: 960
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: (nearly) ieee 754 floating point single precisition

#37 Post by einstein1969 » 20 Aug 2014 12:10

Hi penpen,

very nice work 8) but the macro version is slower... :(

This example for execute the code about 3-5X faster.

Code: Select all

@echo off
setlocal enableExtensions

:: load all macros, and exit if it has failed for whatever reasons
call loadfloat.cmd
if errorLevel 1 exit /b 1

:: use the macros (names are similar to the function names)
for %%a in (operand1 operand2 result string) do set "%%~a="

(setlocal EnableDelayedExpansion

   set $str2float=
   set $floatAdd=
   set $float2str=
   set $floatSub=
   set $floatMul=
   set $intToHex=

   rem set |more

   for /F "eol== delims==" %%f in ('set') do set "%%f="

   >t0.$$$.tmp echo !time!

   for /L %%N in (1,1,100) do (

      %$str2float% "10" operand1
      %$str2float% "4"  operand2

      %$floatAdd%  "%operand1%" "%operand2%" result
      %$float2str% "%result%" string
      rem echo("10" + "4" = "%string%"

      %$floatSub%  "%operand1%" "%operand2%" result
      %$float2str% "%result%" string
      rem echo("10" - "4" = "%string%"

      %$floatMul%  "%operand1%" "%operand2%" result
      %$float2str% "%result%" string
      rem echo("10" * "4" = "%string%"

   )

endlocal)

<t0.$$$.tmp set /p "t0="

for /F "tokens=1-8 delims=:.," %%a in ("%t0: =0%:%time: =0%") do set /a "a=(((1%%e-1%%a)*60)+1%

%f-1%%b)*6000+1%%g%%h-1%%c%%d, a+=(a>>31) & 8640000"

echo elapsed cs : %a%

del t0.$$$.tmp

endlocal


And for DIVISION why (for the moment) not implement Newton's Method for finding the reciprocal of a floating point number for division?

other link:
- http://en.wikipedia.org/wiki/Fast_inverse_square_root Fast inverse square root the square of this is the reciprocal!
- http://homepage.cs.uiowa.edu/~jones/bcd/divide.html Reciprocal Multiplication, a tutorial

einstein1969
Last edited by einstein1969 on 20 Aug 2014 16:25, edited 1 time in total.

einstein1969
Expert
Posts: 960
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: (nearly) ieee 754 floating point single precisition

#38 Post by einstein1969 » 20 Aug 2014 15:55

foxidrive wrote:It doesn't work as it is missing code...



Hi foxidrive,

With the new code i have rewritten the plasma with new gradient.

Code: Select all

@echo off& setlocal EnableDelayedExpansion&Goto :Init_System

:Main

  :: load all macros, and exit if it has failed for whatever reasons
  call loadfloat.cmd
  if errorLevel 1 exit /b 1

  call :create_palette

  set /a e=Lenp/2

  for /L %%y in (-30,1,30) do (


    %$str2float% "%%y" fy

    :: newy=fy/8                                1/4=0x3E800000  1/8=0x3E000000
    rem call :floattestMul2 "1" "0.25" newy

    %$floatMul% "!fy!" "0x3E800000" newy
    %$float2str% "!newy!" newy
    call :sin2 "!newy!" siny
    %$str2float% "!siny!" fy
    %$str2float% "!e!" fe
    %$floatMul% "!fy!" "!fe!" y1
    %$float2str% "!y1!" y1

    :: get integer part
    set app1=!y1:*e-=!

    if not "!y1!"=="!app1!" (set app=0) else (
        set app=!y1:*.=!
        for %%a in (!app!) do set app=!y1:.%%a=!
      )

    if "!app!"=="." set app=0
    set /a iy=e+!app!

    for /L %%x in (-60,1,60) do (

set t0=!time!

      %$str2float% "%%x" "fx"
      %$floatMul% "!fx!" "0x3E800000" newx
      %$float2str% "!newx!" "newx"

set t1=!time!

      call :sin2 "!newx!" sinx

set t2=!time!

      %$str2float% "!sinx!" fx
      %$str2float% "!e!" fe
      %$floatMul% "!fx!" "!fe!" x1
      %$float2str% "!x1!" x1

set t3=!time!

      :: get integer part
      set app1=!x1:*e-=!

      if not "!x1!"=="!app1!" (set app=0) else (
        set app=!x1:*.=!
        for %%a in (!app!) do set app=!x1:.%%a=!
      )

      if "!app!"=="." set app=0
      set /a ix=e+!app!
 
      set /a "c=(ix+iy)/2"

      call :plot !c!

    )

   echo(
  )

Goto :EndMain

:sin2 %1=x radiants
   set x=%~1

   if "%x:~0,1%"=="-" (
     set r=-1
     set x=!x:~1!
   ) else (
     set r=1
   )

   rem calculate SIN(x) ~ x * ( 1 - x^2 * (1/6 - x^2 * (1/120 - x^2 * (1/5040 - x^2 * (1/362880

- x^2 * 1/39916800 )))))

   %$str2float% "%x%" "fx"

:sin2_PI

   :: 0x40490FDB=3.14159265....
   %$floatSub% "%fx%" "0x40490FDB" "tx"

   if !tx! gtr 0 (set /A fx=tx, r=-r) else goto :sin2_cont
   goto :sin2_PI

:sin2_cont

   %$floatMul% "%fx%"       "%fx%"       "fxx"
   %$floatMul% "%fxx%"      "0x32D7322B" "fsinp"
   %$floatSub% "0x3638EF1D" "%fsinp%"    "fsinp2"
   %$floatMul% "%fxx%"      "%fsinp2%"   "fsinp3"
   %$floatSub% "0x39500D01" "%fsinp3%"   "fsinp4"
   %$floatMul% "%fxx%"      "%fsinp4%"   "fsinp5"
   %$floatSub% "0x3C088889" "%fsinp5%"   "fsinp6"
   %$floatMul% "%fxx%"      "%fsinp6%"   "fsinp7"
   %$floatSub% "0x3E2AAAAB" "%fsinp7%"   "fsinp8"
   %$floatMul% "%fxx%"      "%fsinp8%"   "fsinp9"
   %$floatSub% "0x3F800000" "%fsinp9%"   "fsinp10"
   %$floatMul% "%fx%"       "%fsinp10%"  "fsin"

   if !r! lss 0 set /A "fsin=(1<<31)^fsin"

   %$float2str% "%fsin%" "sin"

   set "%~2=%sin%"

goto :eof


:plot %1

 call :color !p[%1]:~0,2! !p[%1]:~-1!

goto :eof


::manual palette, best color add,  rif. http://en.wikipedia.org/wiki/Web_colors
rem
rem 1 -> 2 3 4 5 6 9
rem 2 -> 1 3 4 5 6 A
rem 3 -> 1 2 4 5 6 9 A B
rem 4 -> 1 2 3 5 6 C
rem 5 -> 1 2 3 4 6 9 D
rem 6 -> E
rem 9 -> 1 3 5
rem A -> 2 3 6
rem B -> 3
rem C -> 4 5 6
rem D -> 5
rem E -> 6


:create_palette %1

  set p=0
  rem For %%p in (04 4C cE EA A2 21 15 50) do (
  For %%p in (04 4C c5 53 39 91 15 50) do (
 
    set "p[!p!]=%%p°" & set /a p+=1
    set "p[!p!]=%%p±" & set /a p+=1
    set "p[!p!]=%%p²" & set /a p+=1
    set "p[!p!]=%%pÛ" & set /a p+=1

  )

  set /a p-=1
  set Lenp=!p!

goto :eof

Goto :EndMain

:: ( Begin Color Function

:color

    (echo %~2\..\'
    ) > $$$.color.txt && findstr /a:%~1 /f:$$$.color.txt "."

    Shift
    Shift

    If ""=="%~1" Goto :Eof

   goto :color

:: ) End color Fuction


:Init_system

  for /F "delims==" %%f in ('set') do if /i not "%%f"=="Path" set "%%f="

  for /F "tokens=1,2 delims=#" %%a in ('"prompt #$H#$E# & echo on & for %%b in (1) do rem"') do

(
  set "DEL=%%a")
 
  <nul set /p ".=%DEL%%DEL%%DEL%%DEL%%DEL%%DEL%" > "'"

Goto :Main

:EndMain
  :: Clearing all garbage
  del '
Goto :Eof


It's slower than precedent, but it's possible use the trick of "empty the environment" and the trick of "while in a for loop" for achieve a 3-5X faster execute.

EDIT:

this is little optimized code which show how to maintain the env empty even with a call at subroutine.

Code: Select all

@echo off& setlocal EnableDelayedExpansion&Goto :Init_System

:Main

  :: load all macros, and exit if it has failed for whatever reasons
  call loadfloat.cmd
  if errorLevel 1 exit /b 1

  call :create_palette

  set /a e=Lenp/2

  for /L %%y in (-16,1,16) do (

    %$str2float% "%%y" fy

    :: newy=fy/8                                1/4=0x3E800000  1/8=0x3E000000
    rem call :floattestMul2 "1" "0.25" newy

    %$floatMul% "!fy!" "0x3E800000" newy
    %$float2str% "!newy!" newy

    call :sin2 "!newy!" siny

    %$str2float% "!siny!" fy
    %$str2float% "!e!" fe
    %$floatMul% "!fy!" "!fe!" y1
    %$float2str% "!y1!" y1

    :: get integer part
    set app=!y1:*e-=!

    if not "!y1!"=="!app!" (set app=0) else (
        set app=!y1:*.=!
        for %%a in (!app!) do set app=!y1:.%%a=!
      )

    if "!app!"=="." set app=0
    set /a iy=e+!app!
    set app=

    for /L %%x in (-16,1,16) do (

      %$str2float% "%%x" "fx"
      %$floatMul% "!fx!" "0x3E800000" newx
      %$float2str% "!newx!" "newx"

      call :sin2 "!newx!" sinx

      %$str2float% "!sinx!" fx
      %$str2float% "!e!" fe
      %$floatMul% "!fx!" "!fe!" x1
      %$float2str% "!x1!" x1

      :: get integer part
      set app=!x1:*e-=!

      if not "!x1!"=="!app!" (set app=0) else (
        set app=!x1:*.=!
        for %%a in (!app!) do set app=!x1:.%%a=!
      )

      if "!app!"=="." set app=0
      set /a ix=e+!app!
      set app=
 
      set /a "c=(ix+iy)/2"

      call :plot !c!

    )

   echo(
  )

Goto :EndMain

rem calculate SIN(x) ~ x * ( 1 - x^2 * (1/6 - x^2 * (1/120 - x^2 * (1/5040 - x^2 * (1/362880 - x^2 * 1/39916800 )))))

:sin2 %1=x radiants

   call loadfloat.cmd

(
   set $str2float=
   set $floatAdd=
   set $float2str=
   set $floatSub=
   set $floatMul=
   set $intToHex=

   rem set & pause

   set x=%~1

   if "!x:~0,1!"=="-" (
     set r=-1
     set x=!x:~1!
   ) else (
     set r=1
   )

   %$str2float% "!x!" "fx"

   :: PI=3.14159265....=0x40490FDB
   set break=
   for /L %%I in (1,1,10) do if not defined break (
      %$floatSub% "!fx!" "0x40490FDB" tx
      if !tx! gtr 0 (set /A fx=tx, r=-r) else set break=true
   )
   set break=

   %$floatMul% "!fx!"       "!fx!"       fxx
   %$floatMul% "!fxx!"      "0x32D7322B" fsint
   %$floatSub% "0x3638EF1D" "!fsint!"    fsint
   %$floatMul% "!fxx!"      "!fsint!"    fsint
   %$floatSub% "0x39500D01" "!fsint!"    fsint
   %$floatMul% "!fxx!"      "!fsint!"    fsint
   %$floatSub% "0x3C088889" "!fsint!"    fsint
   %$floatMul% "!fxx!"      "!fsint!"    fsint
   %$floatSub% "0x3E2AAAAB" "!fsint!"    fsint
   %$floatMul% "!fxx!"      "!fsint!"    fsint
   %$floatSub% "0x3F800000" "!fsint!"    fsint
   %$floatMul% "!fx!"       "!fsint!"    fsin

   set fsint=
   set fx=
   set fxx=

   if !r! lss 0 set /A "fsin=(1<<31)^fsin"

   %$float2str% "!fsin!" sin

   set "%~2=!sin!"

   set fsin=
   set sin=

goto :eof )


:plot %1

 call :color !p[%1]:~0,2! !p[%1]:~-1!

goto :eof


::manual palette, best transient color,  rif.http://en.wikipedia.org/wiki/Web_colors
rem
rem 1 -> 2 3 4 5 6 9
rem 2 -> 1 3 4 5 6 A
rem 3 -> 1 2 4 5 6 9 A B
rem 4 -> 1 2 3 5 6 C
rem 5 -> 1 2 3 4 6 9 D
rem 6 -> E
rem 9 -> 1 3 5
rem A -> 2 3 6
rem B -> 3
rem C -> 4 5 6
rem D -> 5
rem E -> 6


:create_palette %1

  set p=0
  rem For %%p in (04 4C cE EA A2 21 15 50) do (
  For %%p in (04 4C c5 53 39 91 15 50) do (
 
    set "p[!p!]=%%p°" & set /a p+=1
    set "p[!p!]=%%p±" & set /a p+=1
    set "p[!p!]=%%p²" & set /a p+=1
    set "p[!p!]=%%pÛ" & set /a p+=1

  )

  set /a p-=1
  set Lenp=!p!

goto :eof

Goto :EndMain

:: ( Begin Color Function

:color

    (echo %~2\..\'
    ) > $$$.color.txt && findstr /a:%~1 /f:$$$.color.txt "."

    Shift
    Shift

    If ""=="%~1" Goto :Eof

   goto :color

:: ) End color Fuction


:Init_system

  for /F "delims==" %%f in ('set') do if /i not "%%f"=="Path" set "%%f="

  for /F "tokens=1,2 delims=#" %%a in ('"prompt #$H#$E# & echo on & for %%b in (1) do rem"') do (
  set "DEL=%%a")
 
  <nul set /p ".=%DEL%%DEL%%DEL%%DEL%%DEL%%DEL%" > "'"

Goto :Main

:EndMain
  :: Clearing all garbage
  del '
Goto :Eof




EDIT: I have added code optimized for performance.

einstein1969

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

Re: (nearly) ieee 754 floating point single precisition

#39 Post by foxidrive » 22 Aug 2014 11:08

einstein1969 wrote:
foxidrive wrote:It doesn't work as it is missing code...



Hi foxidrive,

With the new code i have rewritten the plasma with new gradient.

einstein1969


It doesn't work here - generates an error and aborts.

einstein1969
Expert
Posts: 960
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: (nearly) ieee 754 floating point single precisition

#40 Post by einstein1969 » 22 Aug 2014 11:59

:? Can you try the last version? I have written in the other thread. It's simple to debug. Post output in the other thread.

thanks!

einstein1969
Expert
Posts: 960
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: (nearly) ieee 754 floating point single precisition

#41 Post by einstein1969 » 23 May 2024 06:40

Hi penpen,

After a long time I'm studying this project of yours. I imagine you've forgotten a bit how it works by now. But if you want to help me understand it at least a little, I will be truly grateful.

I'm starting to study how what you did works, also getting help from what I find on the web. But there's so much stuff I'm missing. Then you have to consider that I don't have strong understanding skills and therefore it takes me a very long time to understand.

First of all I'm studying the function that takes a string and transforms it into ieee754 using 32bit. The "str2float"

I still don't know how the complex operation is accomplished. I'm trying to create a simpler one just to understand how it works.

I have decided for the moment to neglect the whole part that deals with the inf, nan, hex values.

I took the comments you put in the procedure, to understand the steps. But I have a lot of difficulty.
  • divide into parts: sPart * iPart.fPart * 10^^ePart
    I understood this part.
     
  • set sign flag(s)
    I understood this part.
     
  • detect NaN, inf and hex format
    I skipped this part for now.
     
  • normalize to: sPart * 0.significand * 10^ePart, 0.significand >= 0.1 AND detect 0.0
    I'm having trouble with this part.
     
    first of all what do you mean here: "0.significand >= 0.1"?
this is the code that studing at moment:

Code: Select all

   ) else (
      for /F "tokens=* delims= " %%a in ("!iPart:0= !") do @set "iPartP=%%~a"
      for /F "tokens=* delims= " %%a in ("!fPart:0= !") do @set "fPartP=%%~a"
      
      if "!iPartP!!fPartP!" == "" (
         >nul set /A "float=s"
      ) else (
         if defined iPartP (
            set "iPartP=!iPartP: =0!"
            set "fPartP=!fPart!"
            set "string= !iPartP!"
            set "op=+"
         ) else if defined fPartP (
            set "fPartP=!fPartP: =0!"
            for %%a in (!fPartP!) do @set "string= !fPart:%%a=!"
            set "op=-"
         )
         
         for %%a in (4096,2048,1024,512,256,128,64,32,16,8,4,2,1) do @if not "!string:~%%a,1!" == "" (
            set "string=!string:~%%a!"
            >nul set /A "ePart!op!=%%a"
         )
         
         set "significand=!iPartP!!fPartP!"
         set "iPartP="
         set "fPartP="
here I understand that you have to calculate the number of digits to move the decimal point. And then you add them or subtract them from the exponent.
And then join the integer part and the fractional part together.

Did I get it right?

if the number is "10.3" , significand=103 and ePart=2 ?

if the number is "99.3", significand=993 and ePart=2 ?

if the number is "0.03", significand=3 and ePart=-1 ?
Last edited by einstein1969 on 23 May 2024 06:53, edited 1 time in total.

einstein1969
Expert
Posts: 960
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: (nearly) ieee 754 floating point single precisition

#42 Post by einstein1969 » 23 May 2024 06:50

This is the very simplified version I'm working on:

Code: Select all

:str2float_very_simple string var_float

   set "string=%~1"
   set "string= !string: =!"

rem for now I only consider numbers without epart
   set "ePart=0"

   set "fPart=!string:*.=!"
   if "!string!" == "!fPart!" ( set "fPart=0" ) else for %%a in ("!fPart!") do @set "string=!string:.%%~a=!"

   set "sPart="
   if "!string:~1,1!" == "-" (
      set "iPart=!string:~2!"
      set "sPart=-"
   ) else if "!string:~1,1!" == "+" (
      set "iPart=!string:~2!"
   ) else set "iPart=!string:~1!"

   rem echo string=%1 s=!spart! i=!ipart! f=!fpart!

   if defined sPart ( set /A "s=1<<31" ) else ( set "s=0" )

   rem echo string=%1 s=!spart![!s!] i=!ipart! f=!fpart!

::   normalize to: sPart * 0.significand * 10^ePart, 0.significand >= 0.1
::   AND
::   detect 0.0

   set "float="

   for /F "tokens=* delims= " %%a in ("!iPart:0= !") do set "iPartP=%%~a"
   for /F "tokens=* delims= " %%a in ("!fPart:0= !") do set "fPartP=%%~a"
      
   echo string=%1 s=!spart![!s!] i=!ipart! f=!fpart! iPartP=[!iPartP!] fPartP=[!fPartP!] ePart=!ePart!

      if "!iPartP!!fPartP!" == "" (
         >nul set /A "float=s"
      ) else (
         if defined iPartP (
            set "iPartP=!iPartP: =0!"
            set "fPartP=!fPart!"
            set "string= !iPartP!"
            set "op=+"
         ) else if defined fPartP (
            set "fPartP=!fPartP: =0!"
            for %%a in (!fPartP!) do set "string= !fPart:%%a=!"
            set "op=-"
         )
         
         for %%a in (4096,2048,1024,512,256,128,64,32,16,8,4,2,1) do if not "!string:~%%a,1!" == "" (
            set "string=!string:~%%a!"
            >nul set /A "ePart!op!=%%a"
         )
         
   echo string=%1 s=!spart![!s!] i=!ipart! f=!fpart! iPartP=[!iPartP!] fPartP=[!fPartP!] ePart=!ePart!

         set "significand=!iPartP!!fPartP!"
         set "iPartP="
         set "fPartP="

   echo string=%1 s=!spart![!s!] i=!ipart! f=!fpart! significand=!significand! ePart=!ePart!

      )


goto :eof

penpen
Expert
Posts: 2009
Joined: 23 Jun 2013 06:15
Location: Germany

Re: (nearly) ieee 754 floating point single precisition

#43 Post by penpen » 23 May 2024 17:13

Yes, you got it right so far.

If i remember right, then the basic idea is to start with a number string in scientific notation,
transform that into a decimal floating point representation with exponent to base ten (sign, decimal number, exponent to base 10),
transform that into a decimal floating point representation with exponent to base two (sign, decimal number, exponent to base 2) and
normalize that value such that 1 <= decimal number (d) < 2,
so that we can apply the following algorithm (in c-like notation and ignoring rounding here) to calculate the binary number representation (f):

Code: Select all

// The following is kinda like f := floor(d * 2^24):
f = 0;
for (int i = 0; i <= 24; ++i) {
	if (d >= 1) {
	 f = 2 * (f+1);
	 d = 2 * (d-1);
	} else {
	 f = 2 * f;
	 d = 2 * d;
	}
}

Since batch is limited, i added some extra steps (to ensure beeing in a defined state) and used an unusual high-low number representation, which makes the code harder to read.


penpen

einstein1969
Expert
Posts: 960
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: (nearly) ieee 754 floating point single precisition

#44 Post by einstein1969 » 24 May 2024 09:11

Thanks a lot. Yes, in fact, the code I am reading is very difficult and it will take me a long time.

You can give me an example with a "number" because it's not yet clear to me:

"If i Remember Right, then the basic idea is to start with a number string in scientific notation" Example .....
"Transform that into a decimal floating point represement with exponent to base ten (sign, decimal number, exponent to base 10)" Example .....
Transform that into a decimal floating point represement with exponent to base Two (sign, decimal number, exponent to base 2) Example .....

Then this part how to do it?
"normalize that value such That 1 <= decimal number (D) <2" Example .....

penpen
Expert
Posts: 2009
Joined: 23 Jun 2013 06:15
Location: Germany

Re: (nearly) ieee 754 floating point single precisition

#45 Post by penpen » 24 May 2024 14:20

Then this part how to do it?
"normalize that value such That 1 <= decimal number (d) <2" Example .....
After (finally) looking at the code, I would say (in case i didn't msiread my code), that i used a strlength algorithm on d, to shift the first non 0 digit at the first place of after the decimal seperator, such that 0.1 < d < 1.
Then I shift d left by one decimal digit, such that 1 <= d < 10.
Then if needed, I divide d by 2 until 1 <= d < 2.

Here is a short example:

Code: Select all

"-2469.1356E-9"
= -2469.1356 * 10^-9                        ;  iPart=2469; fPart= 1356; ePart=-9
                                            ; (strlen algorithm)
= -0.24691356 * 10^-5                       ;  sPart=-; significand=24691356; ePart=-5 (normalized to 0.1 <= 0.24691356 < 1, in order to avoid case disctinctions)
= -0.24691356000000000 * 10^-5              ;  sPart=-; significand=24691356000000000; ePart=-5 (extend to 17 digits; more wouldn't be noticed anyways)
= -2.4691356000000000 * 10^-6               ;  sPart=-; high=246913560; low=00000000; ePart=-6 (high: 9 digits, low part 8 digits)
= -2.4691356000000000 * 2^-6  * 5^-6        ;  sPart=-; high=246913560; low=00000000; e_2=-6; ePart=-6
                                            ;  divide h.ighlow by 2 (updating the e_2 value) until 1 <= h.ighlow < 2
= -1.2345678000000000 * 2^-5  * 5^-6        ;  sPart=-; high=123456780; low=00000000; e_2=-5; ePart=-6
= -0.12345678000000000 * 2^-4  * 5^-5
= -1.9753084800000000 * 2^-8  * 5^-5        ;  sPart=-; high=197530848; low=00000000; e_2 =-8; ePart=-5
= ...
= -1.2945381654528000 * 2^-19 * 5^0         ;  sPart=-; high=129453816; low=54528000; e_2=-19

==> s = 1
and e = 127-19 = 108 = 1101100_2
and f = floor(1.2945381654528000 * 2^24) = 21718746 = 101001011011001101101101_2
e != 255 ==> normalized number
==> ieee_value = [s (1 bit), e (8 bit), f without leading 1 (23 bit)] = [1, 01101100, 01001011011001101101101]_2 = 10110101101001011011001101101101_2 = -1239043219
Sidenote:
If the number were denormalized, then no bit is removed (= the highest 23 bits are used to encode the ieee_value).


penpen

Post Reply