File: mflpt.a

package info (click to toggle)
acme 1%3A0.96.2-1
  • links: PTS
  • area: main
  • in suites: buster
  • size: 1,360 kB
  • sloc: ansic: 8,071; makefile: 91; sh: 53
file content (87 lines) | stat: -rw-r--r-- 2,982 bytes parent folder | download
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
;ACME 0.94.5

!ifdef lib_cbm_mflpt_a !eof
lib_cbm_mflpt_a = 1

; CAUTION! The Commodore BASIC interpreter uses two different formats for
; handling floating-point values, so do not confuse them:
; The "float registers" fac1 and fac2 (actually structures in zero page) use a
; six-byte format commonly known as "flpt" (floating point).
; When storing values in variables (or reading values from ROM), a compressed
; five-byte format is used, commonly known as "mflpt" (memory floating point).

; This file contains a macro for writing floating point numbers in the five-byte
; "mflpt" format, where the sign bit is packed into the mantissa.
; Several interpreter functions use this format (see <cbm/c64/float.a>).

; Use the macro like this:
;		+mflpt 3.1415926	; each use will take up five bytes of memory


; now for the technical stuff (stop reading right now if you value your sanity)

; five-byte layout in memory:
; eeeeeeee smmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm	; eight bits exponent, 32 bits mantissa with sign bit overlay

; exponent byte:
;	exponent has a bias of 128 (128 means the decimal point is right before the mantissa's leading digit)
;	if exponent is zero, number value is considered to be zero, regardless of mantissa
;	exponents 1..128 are for values < 1
;	exponents 129..255 are for values >= 1

; mantissa:
;	mantissa is stored big-endian(!)
;	the mantissa's mandatory leading '1' is replaced by the sign bit

; so logically, this is equivalent to:
; + .1mmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm * 2^(eeeeeeee - 128) if sign bit is 0
; - .1mmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm * 2^(eeeeeeee - 128) if sign bit is 1



; this is ugly, but it gets the job done
; (if it's stupid, but it works, then it's not stupid)
!macro mflpt .value {
	!set .float = float(.value)	; make sure to do passes until value is defined
	!ifndef .float {
		!by $ff, $ff, $ff, $ff, $ff	; five place holder bytes
	} else {
		; value is defined, so split up into sign and non-negative value
		!if .float < 0 {
			!set .sign = $80
			!set .float = -.float
		} else {
			!set .sign = $00
		}
		!if .float = 0 {
			!by 0, 0, 0, 0, 0	; five zeroes (zero is represented by all bits zero)
		} else {
			; split up into exponent and mantissa
			!set .exponent = 128 + 32	; 128 is cbm's bias, 32 is this algo's bias
			; if mantissa is too large, shift right and adjust exponent
			!do while .float >= (2.0 ^ 32.0) {
				!set .float = .float >> 1
				!set .exponent = .exponent + 1
			}
			; if mantissa is too small, shift left and adjust exponent
			!do while .float < (2.0 ^ 31.0) {
				!set .float = .float << 1
				!set .exponent = .exponent - 1
			}
			!if .exponent < 1 {
				!warn "MFLPT underflow, using zero instead"
				!set .float = 0
				!set .exponent = 0
				!set .sign = 0
			}
			!if .exponent > 255 {
				!error "MFLPT overflow"
			}
			!by .exponent
			!by (127 & int(.float >> 24)) | .sign
			!by 255 & int(.float >> 16)
			!by 255 & int(.float >> 8)
			!by 255 & int(.float)
		}
	}
}