https://github.com/akkartik/mu/blob/main/linux/412print-float-decimal.mu
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 fn test-write-float-decimal-approximate-normal {
26 var s-storage: (stream byte 0x10)
27 var s/ecx: (addr stream byte) <- address s-storage
28
29 var half/xmm0: float <- rational 1, 2
30 write-float-decimal-approximate s, half, 3
31 check-stream-equal s, "0.5", "F - test-write-float-decimal-approximate-normal 0.5"
32
33 clear-stream s
34 var quarter/xmm0: float <- rational 1, 4
35 write-float-decimal-approximate s, quarter, 3
36 check-stream-equal s, "0.25", "F - test-write-float-decimal-approximate-normal 0.25"
37
38 clear-stream s
39 var three-quarters/xmm0: float <- rational 3, 4
40 write-float-decimal-approximate s, three-quarters, 3
41 check-stream-equal s, "0.75", "F - test-write-float-decimal-approximate-normal 0.75"
42
43 clear-stream s
44 var eighth/xmm0: float <- rational 1, 8
45 write-float-decimal-approximate s, eighth, 3
46 check-stream-equal s, "0.125", "F - test-write-float-decimal-approximate-normal 0.125"
47
48 clear-stream s
49 var sixteenth/xmm0: float <- rational 1, 0x10
50 write-float-decimal-approximate s, sixteenth, 3
51 check-stream-equal s, "6.25e-2", "F - test-write-float-decimal-approximate-normal 0.0625"
52
53 clear-stream s
54 var two-f/xmm0: float <- rational 2, 1
55 var sqrt-2/xmm0: float <- square-root two-f
56 write-float-decimal-approximate s, sqrt-2, 3
57 check-stream-equal s, "1.414", "F - test-write-float-decimal-approximate-normal √2"
58 }
59
60
61 fn test-write-float-decimal-approximate-integer {
62 var s-storage: (stream byte 0x10)
63 var s/ecx: (addr stream byte) <- address s-storage
64
65 var one-f/xmm0: float <- rational 1, 1
66 write-float-decimal-approximate s, one-f, 3
67 check-stream-equal s, "1", "F - test-write-float-decimal-approximate-integer 1"
68
69 clear-stream s
70 var two-f/xmm0: float <- rational 2, 1
71 write-float-decimal-approximate s, two-f, 3
72 check-stream-equal s, "2", "F - test-write-float-decimal-approximate-integer 2"
73
74 clear-stream s
75 var ten-f/xmm0: float <- rational 0xa, 1
76 write-float-decimal-approximate s, ten-f, 3
77 check-stream-equal s, "10", "F - test-write-float-decimal-approximate-integer 10"
78
79 clear-stream s
80 var minus-ten-f/xmm0: float <- rational -0xa, 1
81 write-float-decimal-approximate s, minus-ten-f, 3
82 check-stream-equal s, "-10", "F - test-write-float-decimal-approximate-integer -10"
83
84 clear-stream s
85 var minus-ten-f/xmm0: float <- rational 0x3e7, 1
86 write-float-decimal-approximate s, minus-ten-f, 3
87 check-stream-equal s, "999", "F - test-write-float-decimal-approximate-integer 1000"
88
89 clear-stream s
90 var minus-ten-f/xmm0: float <- rational 0x3e8, 1
91 write-float-decimal-approximate s, minus-ten-f, 3
92 check-stream-equal s, "1.00e3", "F - test-write-float-decimal-approximate-integer 1000"
93
94 clear-stream s
95 var hundred-thousand/eax: int <- copy 0x186a0
96 var hundred-thousand-f/xmm0: float <- convert hundred-thousand
97 write-float-decimal-approximate s, hundred-thousand-f, 3
98 check-stream-equal s, "1.00e5", "F - test-write-float-decimal-approximate-integer 100,000"
99 }
100
101 fn test-write-float-decimal-approximate-zero {
102 var s-storage: (stream byte 0x10)
103 var s/ecx: (addr stream byte) <- address s-storage
104 var zero: float
105 write-float-decimal-approximate s, zero, 3
106 check-stream-equal s, "0", "F - test-write-float-decimal-approximate-zero"
107 }
108
109 fn test-write-float-decimal-approximate-negative-zero {
110 var s-storage: (stream byte 0x10)
111 var s/ecx: (addr stream byte) <- address s-storage
112 var n: int
113 copy-to n, 0x80000000
114 var negative-zero/xmm0: float <- reinterpret n
115 write-float-decimal-approximate s, negative-zero, 3
116 check-stream-equal s, "-0", "F - test-write-float-decimal-approximate-negative-zero"
117 }
118
119 fn test-write-float-decimal-approximate-infinity {
120 var s-storage: (stream byte 0x10)
121 var s/ecx: (addr stream byte) <- address s-storage
122 var n: int
123
124
125 copy-to n, 0x7f800000
126 var infinity/xmm0: float <- reinterpret n
127 write-float-decimal-approximate s, infinity, 3
128 check-stream-equal s, "Inf", "F - test-write-float-decimal-approximate-infinity"
129 }
130
131 fn test-write-float-decimal-approximate-negative-infinity {
132 var s-storage: (stream byte 0x10)
133 var s/ecx: (addr stream byte) <- address s-storage
134 var n: int
135 copy-to n, 0xff800000
136 var negative-infinity/xmm0: float <- reinterpret n
137 write-float-decimal-approximate s, negative-infinity, 3
138 check-stream-equal s, "-Inf", "F - test-write-float-decimal-approximate-negative-infinity"
139 }
140
141 fn test-write-float-decimal-approximate-not-a-number {
142 var s-storage: (stream byte 0x10)
143 var s/ecx: (addr stream byte) <- address s-storage
144 var n: int
145 copy-to n, 0xffffffff
146 var nan/xmm0: float <- reinterpret n
147 write-float-decimal-approximate s, nan, 3
148 check-stream-equal s, "NaN", "F - test-write-float-decimal-approximate-not-a-number"
149 }
150
151 fn print-float-decimal-approximate screen: (addr screen), in: float, precision: int {
152 var s-storage: (stream byte 0x10)
153 var s/esi: (addr stream byte) <- address s-storage
154 write-float-decimal-approximate s, in, precision
155 print-stream screen, s
156 }
157
158
159 fn write-float-decimal-approximate out: (addr stream byte), in: float, precision: int {
160
161 var bits/eax: int <- reinterpret in
162 compare bits, 0
163 {
164 break-if-!=
165 write out, "0"
166 return
167 }
168 compare bits, 0x80000000
169 {
170 break-if-!=
171 write out, "-0"
172 return
173 }
174 compare bits, 0x7f800000
175 {
176 break-if-!=
177 write out, "Inf"
178 return
179 }
180 compare bits, 0xff800000
181 {
182 break-if-!=
183 write out, "-Inf"
184 return
185 }
186 var exponent/ecx: int <- copy bits
187 exponent <- shift-right 0x17
188 exponent <- and 0xff
189 exponent <- subtract 0x7f
190 compare exponent, 0x80
191 {
192 break-if-!=
193 write out, "NaN"
194 return
195 }
196
197 var sign/edx: int <- copy bits
198 sign <- shift-right 0x1f
199 {
200 compare sign, 1
201 break-if-!=
202 append-byte out, 0x2d/minus
203 }
204
205
206 var v/ebx: int <- copy bits
207 v <- and 0x7fffff
208 v <- or 0x00800000
209
210 var e/ecx: int <- copy exponent
211 e <- subtract 0x17
212
213
214
215 var buf-storage: (array byte 0x7f)
216 var buf/edi: (addr array byte) <- address buf-storage
217 var n/eax: int <- decimal-digits v, buf
218
219
220 reverse-digits buf, n
221
222
223 {
224 compare e, 0
225 break-if-<=
226 n <- double-array-of-decimal-digits buf, n
227 e <- decrement
228 loop
229 }
230
231 var dp/edx: int <- copy n
232
233
234 {
235 compare e, 0
236 break-if->=
237 n, dp <- halve-array-of-decimal-digits buf, n, dp
238 e <- increment
239 loop
240 }
241
242 _write-float-array-of-decimal-digits out, buf, n, dp, precision
243 }
244
245
246
247 fn decimal-digits n: int, _buf: (addr array byte) -> _/eax: int {
248 var buf/edi: (addr array byte) <- copy _buf
249 var i/ecx: int <- copy 0
250 var curr/eax: int <- copy n
251 var curr-byte/edx: int <- copy 0
252 {
253 compare curr, 0
254 break-if-=
255 curr, curr-byte <- integer-divide curr, 0xa
256 var dest/ebx: (addr byte) <- index buf, i
257 copy-byte-to *dest, curr-byte
258 i <- increment
259 loop
260 }
261 return i
262 }
263
264 fn reverse-digits _buf: (addr array byte), n: int {
265 var buf/esi: (addr array byte) <- copy _buf
266 var left/ecx: int <- copy 0
267 var right/edx: int <- copy n
268 right <- decrement
269 {
270 compare left, right
271 break-if->=
272 {
273 var l-a/ecx: (addr byte) <- index buf, left
274 var r-a/edx: (addr byte) <- index buf, right
275 var l/ebx: byte <- copy-byte *l-a
276 var r/eax: byte <- copy-byte *r-a
277 copy-byte-to *l-a, r
278 copy-byte-to *r-a, l
279 }
280 left <- increment
281 right <- decrement
282 loop
283 }
284 }
285
286
287 fn dump-digits _buf: (addr array byte), count: int, msg: (addr array byte) {
288 var buf/edi: (addr array byte) <- copy _buf
289 var i/ecx: int <- copy 0
290 print-string 0, msg
291 print-string 0, ": "
292 {
293 compare i, count
294 break-if->=
295 var curr/edx: (addr byte) <- index buf, i
296 var curr-byte/eax: byte <- copy-byte *curr
297 var curr-int/eax: int <- copy curr-byte
298 print-int32-decimal 0, curr-int
299 print-string 0, " "
300 break-if-=
301 i <- increment
302 loop
303 }
304 print-string 0, "\n"
305 }
306
307 fn double-array-of-decimal-digits _buf: (addr array byte), _n: int -> _/eax: int {
308 var buf/edi: (addr array byte) <- copy _buf
309
310 var delta/edx: int <- copy 0
311 {
312 var curr/ebx: (addr byte) <- index buf, 0
313 var tmp/eax: byte <- copy-byte *curr
314 compare tmp, 5
315 break-if-<
316 delta <- copy 1
317 }
318
319 var x/eax: int <- copy 0
320 var i/ecx: int <- copy _n
321 i <- decrement
322 {
323 compare i, 0
324 break-if-<=
325
326 {
327 var tmp/ecx: (addr byte) <- index buf, i
328 var tmp2/ecx: byte <- copy-byte *tmp
329 x <- add tmp2
330 x <- add tmp2
331 }
332
333 {
334 var dest-index/ecx: int <- copy i
335 dest-index <- add delta
336 var dest/edi: (addr byte) <- index buf, dest-index
337 var next-digit/edx: int <- copy 0
338 x, next-digit <- integer-divide x, 0xa
339 copy-byte-to *dest, next-digit
340 }
341
342 i <- decrement
343 loop
344 }
345
346 var n/eax: int <- copy _n
347 compare delta, 1
348 {
349 break-if-!=
350 var curr/ebx: (addr byte) <- index buf, 0
351 var one/edx: int <- copy 1
352 copy-byte-to *curr, one
353 n <- increment
354 }
355 return n
356 }
357
358 fn halve-array-of-decimal-digits _buf: (addr array byte), _n: int, _dp: int -> _/eax: int, _/edx: int {
359 var buf/edi: (addr array byte) <- copy _buf
360 var n/eax: int <- copy _n
361 var dp/edx: int <- copy _dp
362
363 {
364
365 var right-index/ecx: int <- copy n
366 right-index <- decrement
367 var right-a/ecx: (addr byte) <- index buf, right-index
368 var right/ecx: byte <- copy-byte *right-a
369 var right-int/ecx: int <- copy right
370 var remainder/edx: int <- copy 0
371 {
372 var dummy/eax: int <- copy 0
373 dummy, remainder <- integer-divide right-int, 2
374 }
375 compare remainder, 0
376 break-if-=
377
378 var next-a/ecx: (addr byte) <- index buf, n
379 var zero/edx: byte <- copy 0
380 copy-byte-to *next-a, zero
381
382 n <- increment
383 }
384
385 var delta/ebx: int <- copy 0
386 var x/esi: int <- copy 0
387 {
388
389 var left/ecx: (addr byte) <- index buf, 0
390 var src/ecx: byte <- copy-byte *left
391 compare src, 2
392 break-if->=
393
394 delta <- copy 1
395 x <- copy src
396
397 n <- decrement
398
399 dp <- decrement
400 }
401
402 var i/ecx: int <- copy 0
403 {
404 compare i, n
405 break-if->=
406
407 {
408 var ten/edx: int <- copy 0xa
409 x <- multiply ten
410 var src-index/edx: int <- copy i
411 src-index <- add delta
412 var src-a/edx: (addr byte) <- index buf, src-index
413 var src/edx: byte <- copy-byte *src-a
414 x <- add src
415 }
416
417 {
418 var quotient/eax: int <- copy 0
419 var remainder/edx: int <- copy 0
420 quotient, remainder <- integer-divide x, 2
421 x <- copy remainder
422 var dest/edx: (addr byte) <- index buf, i
423 copy-byte-to *dest, quotient
424 }
425
426 i <- increment
427 loop
428 }
429 return n, dp
430 }
431
432 fn _write-float-array-of-decimal-digits out: (addr stream byte), _buf: (addr array byte), n: int, dp: int, precision: int {
433 var buf/edi: (addr array byte) <- copy _buf
434 {
435 compare dp, 0
436 break-if->=
437 _write-float-array-of-decimal-digits-in-scientific-notation out, buf, n, dp, precision
438 return
439 }
440 {
441 var dp2/eax: int <- copy dp
442 compare dp2, precision
443 break-if-<=
444 _write-float-array-of-decimal-digits-in-scientific-notation out, buf, n, dp, precision
445 return
446 }
447 {
448 compare dp, 0
449 break-if-!=
450 append-byte out, 0x30/0
451 }
452 var i/eax: int <- copy 0
453
454 var limit/edx: int <- copy dp
455 limit <- add 3
456 {
457 compare limit, n
458 break-if-<=
459 limit <- copy n
460 }
461 {
462 compare i, limit
463 break-if->=
464
465 compare i, dp
466 {
467 break-if-!=
468 append-byte out, 0x2e/decimal-point
469 }
470 var curr-a/ecx: (addr byte) <- index buf, i
471 var curr/ecx: byte <- copy-byte *curr-a
472 var curr-int/ecx: int <- copy curr
473 curr-int <- add 0x30/0
474 append-byte out, curr-int
475
476 i <- increment
477 loop
478 }
479 }
480
481 fn _write-float-array-of-decimal-digits-in-scientific-notation out: (addr stream byte), _buf: (addr array byte), n: int, dp: int, precision: int {
482 var buf/edi: (addr array byte) <- copy _buf
483 var i/eax: int <- copy 0
484 {
485 compare i, n
486 break-if->=
487 compare i, precision
488 break-if->=
489 compare i, 1
490 {
491 break-if-!=
492 append-byte out, 0x2e/decimal-point
493 }
494 var curr-a/ecx: (addr byte) <- index buf, i
495 var curr/ecx: byte <- copy-byte *curr-a
496 var curr-int/ecx: int <- copy curr
497 curr-int <- add 0x30/0
498 append-byte out, curr-int
499
500 i <- increment
501 loop
502 }
503 append-byte out, 0x65/e
504 decrement dp
505 write-int32-decimal out, dp
506 }
507
508
509
510 fn float-size in: float, precision: int -> _/eax: int {
511
512 var bits/eax: int <- reinterpret in
513 compare bits, 0
514 {
515 break-if-!=
516 return 1
517 }
518 compare bits, 0x80000000
519 {
520 break-if-!=
521 return 2
522 }
523 compare bits, 0x7f800000
524 {
525 break-if-!=
526 return 3
527 }
528 compare bits, 0xff800000
529 {
530 break-if-!=
531 return 4
532 }
533 var exponent/ecx: int <- copy bits
534 exponent <- shift-right 0x17
535 exponent <- and 0xff
536 exponent <- subtract 0x7f
537 compare exponent, 0x80
538 {
539 break-if-!=
540 return 3
541 }
542
543
544 var v/ebx: int <- copy bits
545 v <- and 0x7fffff
546 v <- or 0x00800000
547
548 var e/ecx: int <- copy exponent
549 e <- subtract 0x17
550
551
552 var buf-storage: (array byte 0x7f)
553 var buf/edi: (addr array byte) <- address buf-storage
554 var n/eax: int <- decimal-digits v, buf
555 reverse-digits buf, n
556
557
558 {
559 compare e, 0
560 break-if-<=
561 n <- double-array-of-decimal-digits buf, n
562 e <- decrement
563 loop
564 }
565
566 var dp/edx: int <- copy n
567
568
569 {
570 compare e, 0
571 break-if->=
572 n, dp <- halve-array-of-decimal-digits buf, n, dp
573 e <- increment
574 loop
575 }
576
577 compare dp, 0
578 {
579 break-if->=
580 return 8
581 }
582 {
583 var dp2/eax: int <- copy dp
584 compare dp2, precision
585 break-if-<=
586 return 8
587 }
588
589
590 var result/ecx: int <- copy dp
591 result <- add 3
592 {
593 compare result, n
594 break-if-<=
595 result <- copy n
596 }
597
598
599 compare dp, n
600 {
601 break-if->=
602 result <- increment
603 }
604
605
606 var sign/edx: int <- reinterpret in
607 sign <- shift-right 0x1f
608 {
609 compare sign, 1
610 break-if-!=
611 result <- increment
612 }
613 return result
614 }
615
616
617
618
619 fn check-buffer-contains _buf: (addr array byte), _contents: (addr array byte), msg: (addr array byte) {
620 var buf/esi: (addr array byte) <- copy _buf
621 var contents/edi: (addr array byte) <- copy _contents
622 var a/eax: boolean <- string-starts-with? buf, contents
623 check a, msg
624 var len/ecx: int <- length contents
625 var len2/eax: int <- length buf
626 compare len, len2
627 break-if-=
628 var c/eax: (addr byte) <- index buf, len
629 var d/eax: byte <- copy-byte *c
630 var e/eax: int <- copy d
631 check-ints-equal e, 0, msg
632 }
633
634 fn test-check-buffer-contains {
635 var arr: (array byte 4)
636 var a/esi: (addr array byte) <- address arr
637 var b/eax: (addr byte) <- index a, 0
638 var c/ecx: byte <- copy 0x61/a
639 copy-byte-to *b, c
640 check-buffer-contains a, "a", "F - test-check-buffer-contains"
641 check-buffer-contains "a", "a", "F - test-check-buffer-contains/null"
642 }