https://github.com/akkartik/mu/blob/main/linux/409print-float-hex.mu
  1 # quick-n-dirty way to print out floats in hex
  2 # https://www.exploringbinary.com/hexadecimal-floating-point-constants
  3 
  4 # example:
  5 #   0.5 = 0x3f000000 = 0011| 1111 | 0000 | 0000 | 0000 | 0000 | 0000 | 0000
  6 #                    = 0 | 01111110 | 00000000000000000000000
  7 #                      +   exponent   mantissa
  8 #                    = 0 | 00000000000000000000000 | 01111110
  9 #                          mantissa                  exponent
 10 #                    = 0 | 000000000000000000000000 | 01111110
 11 #                          zero-pad mantissa          exponent
 12 #                   =   +1.000000                   P -01
 13 fn test-print-float-hex-normal {
 14   var screen-on-stack: screen
 15   var screen/esi: (addr screen) <- address screen-on-stack
 16   initialize-screen screen, 5, 0x20  # 32 columns should be more than enough
 17   # 0.5
 18   var half/xmm0: float <- rational 1, 2
 19   print-float-hex screen, half
 20   check-screen-row screen, 1, "1.000000P-01 ", "F - test-print-float-hex-normal 0.5"
 21   # 0.25
 22   clear-screen screen
 23   var quarter/xmm0: float <- rational 1, 4
 24   print-float-hex screen, quarter
 25   check-screen-row screen, 1, "1.000000P-02 ", "F - test-print-float-hex-normal 0.25"
 26   # 0.75
 27   clear-screen screen
 28   var three-quarters/xmm0: float <- rational 3, 4
 29   print-float-hex screen, three-quarters
 30   check-screen-row screen, 1, "1.800000P-01 ", "F - test-print-float-hex-normal 0.75"
 31   # 0.1
 32   clear-screen screen
 33   var tenth/xmm0: float <- rational 1, 0xa
 34   print-float-hex screen, tenth
 35   check-screen-row screen, 1, "1.99999aP-04 ", "F - test-print-float-hex-normal 0.1"
 36 }
 37 
 38 fn test-print-float-hex-integer {
 39   var screen-on-stack: screen
 40   var screen/esi: (addr screen) <- address screen-on-stack
 41   initialize-screen screen, 5, 0x20  # 32 columns should be more than enough
 42   # 1
 43   var one-f/xmm0: float <- rational 1, 1
 44   print-float-hex screen, one-f
 45   check-screen-row screen, 1, "1.000000P00 ", "F - test-print-float-hex-integer 1"
 46   # 2
 47   clear-screen screen
 48   var two-f/xmm0: float <- rational 2, 1
 49   print-float-hex screen, two-f
 50   check-screen-row screen, 1, "1.000000P01 ", "F - test-print-float-hex-integer 2"
 51   # 10
 52   clear-screen screen
 53   var ten-f/xmm0: float <- rational 0xa, 1
 54   print-float-hex screen, ten-f
 55   check-screen-row screen, 1, "1.400000P03 ", "F - test-print-float-hex-integer 10"
 56   # -10
 57   clear-screen screen
 58   var minus-ten-f/xmm0: float <- rational -0xa, 1
 59   print-float-hex screen, minus-ten-f
 60   check-screen-row screen, 1, "-1.400000P03 ", "F - test-print-float-hex-integer -10"
 61 }
 62 
 63 fn test-print-float-hex-zero {
 64   var screen-on-stack: screen
 65   var screen/esi: (addr screen) <- address screen-on-stack
 66   initialize-screen screen, 5, 0x20  # 32 columns should be more than enough
 67   var zero: float
 68   print-float-hex screen, zero
 69   check-screen-row screen, 1, "0 ", "F - test-print-float-hex-zero"
 70 }
 71 
 72 fn test-print-float-hex-negative-zero {
 73   var screen-on-stack: screen
 74   var screen/esi: (addr screen) <- address screen-on-stack
 75   initialize-screen screen, 5, 0x20  # 32 columns should be more than enough
 76   var n: int
 77   copy-to n, 0x80000000
 78   var negative-zero/xmm0: float <- reinterpret n
 79   print-float-hex screen, negative-zero
 80   check-screen-row screen, 1, "-0 ", "F - test-print-float-hex-negative-zero"
 81 }
 82 
 83 fn test-print-float-hex-infinity {
 84   var screen-on-stack: screen
 85   var screen/esi: (addr screen) <- address screen-on-stack
 86   initialize-screen screen, 5, 0x20  # 32 columns should be more than enough
 87   var n: int
 88   #          0|11111111|00000000000000000000000
 89   #          0111|1111|1000|0000|0000|0000|0000|0000
 90   copy-to n, 0x7f800000
 91   var infinity/xmm0: float <- reinterpret n
 92   print-float-hex screen, infinity
 93   check-screen-row screen, 1, "Inf ", "F - test-print-float-hex-infinity"
 94 }
 95 
 96 fn test-print-float-hex-negative-infinity {
 97   var screen-on-stack: screen
 98   var screen/esi: (addr screen) <- address screen-on-stack
 99   initialize-screen screen, 5, 0x20  # 32 columns should be more than enough
100   var n: int
101   copy-to n, 0xff800000
102   var negative-infinity/xmm0: float <- reinterpret n
103   print-float-hex screen, negative-infinity
104   check-screen-row screen, 1, "-Inf ", "F - test-print-float-hex-negative-infinity"
105 }
106 
107 fn test-print-float-hex-not-a-number {
108   var screen-on-stack: screen
109   var screen/esi: (addr screen) <- address screen-on-stack
110   initialize-screen screen, 5, 0x20  # 32 columns should be more than enough
111   var n: int
112   copy-to n, 0xffffffff  # exponent must be all 1's, and mantissa must be non-zero
113   var negative-infinity/xmm0: float <- reinterpret n
114   print-float-hex screen, negative-infinity
115   check-screen-row screen, 1, "NaN ", "F - test-print-float-hex-not-a-number"
116 }
117 
118 fn print-float-hex screen: (addr screen), n: float {
119   # - special names
120   var bits/eax: int <- reinterpret n
121   compare bits, 0
122   {
123     break-if-!=
124     print-string screen, "0"
125     return
126   }
127   compare bits, 0x80000000
128   {
129     break-if-!=
130     print-string screen, "-0"
131     return
132   }
133   compare bits, 0x7f800000
134   {
135     break-if-!=
136     print-string screen, "Inf"
137     return
138   }
139   compare bits, 0xff800000
140   {
141     break-if-!=
142     print-string screen, "-Inf"
143     return
144   }
145   var exponent/ecx: int <- copy bits
146   exponent <- shift-right 0x17  # 23 bits of mantissa
147   exponent <- and 0xff
148   exponent <- subtract 0x7f
149   compare exponent, 0x80
150   {
151     break-if-!=
152     print-string screen, "NaN"
153     return
154   }
155   # - regular numbers
156   var sign/edx: int <- copy bits
157   sign <- shift-right 0x1f
158   {
159     compare sign, 1
160     break-if-!=
161     print-string screen, "-"
162   }
163   $print-float-hex:leading-digit: {
164     # check for subnormal numbers
165     compare exponent, -0x7f
166     {
167       break-if-!=
168       print-string screen, "0."
169       exponent <- increment
170       break $print-float-hex:leading-digit
171     }
172     # normal numbers
173     print-string screen, "1."
174   }
175   var mantissa/ebx: int <- copy bits
176   mantissa <- and 0x7fffff
177   mantissa <- shift-left 1  # pad to whole nibbles
178   print-int32-hex-bits screen, mantissa, 0x18
179   # print exponent
180   print-string screen, "P"
181   compare exponent, 0
182   {
183     break-if->=
184     print-string screen, "-"
185   }
186   var exp-magnitude/eax: int <- abs exponent
187   print-int32-hex-bits screen, exp-magnitude, 8
188 }
189 
190 #? fn main -> _/ebx: int {
191 #?   run-tests
192 #? #?   test-print-float-hex-negative-zero
193 #? #?   print-int32-hex 0, 0
194 #? #?   test-print-float-hex-normal
195 #?   return 0
196 #? }