316 lines
11 KiB
Plaintext
316 lines
11 KiB
Plaintext
'******************************************************************************
|
|
' Floating Point I/O Routines
|
|
' Author: Dave Hein
|
|
' Copyright (c) 2010
|
|
' See end of file for terms of use.
|
|
'******************************************************************************
|
|
'******************************************************************************
|
|
' Revison History
|
|
' v1.0 - 4/2/2010 First official release
|
|
'******************************************************************************
|
|
{
|
|
These routines are used by the C library to perform formatted floating point
|
|
I/O. The two output routines, putfloate and putfloatf write to string.
|
|
|
|
Input formatting is performed by the strtofloat routine. It uses a pointer
|
|
to a string pointer and returns the resulting floating point value.
|
|
|
|
If floating point I/O is not required for an application this file can be
|
|
removed by deleting the references to the object and the three routines in
|
|
clib.spin.
|
|
}
|
|
|
|
'******************************************************************************
|
|
' Floating Point Routines
|
|
'******************************************************************************
|
|
PUB putfloate(str, x, width, digits) | man, exp10, signbit
|
|
{{
|
|
Convert the floating point value in x to a string of characters in scientific
|
|
notation in str. digits determines the number of fractional digits used and
|
|
width determines the minimum length of the output string. Leading blanks are
|
|
added to achieve the minimum width.
|
|
}}
|
|
if (digits < 0)
|
|
digits := 6
|
|
signbit := tofloat10(x, @man, @exp10)
|
|
exp10 += round10(digits + 1, @man) + digits
|
|
width -= 5 + signbit - (digits <> 0)
|
|
repeat while (width-- > digits)
|
|
byte[str++] := " "
|
|
if (signbit)
|
|
byte[str++] := "-"
|
|
str := utoa10(man, str, 1)
|
|
byte[str++] := "e"
|
|
if (exp10 => 0)
|
|
byte[str++] := "+"
|
|
else
|
|
byte[str++] := "-"
|
|
exp10 := 0-exp10
|
|
if (exp10 < 10)
|
|
byte[str++] := "0"
|
|
str := utoa10(exp10, str, -1)
|
|
byte[str] := 0
|
|
return str
|
|
|
|
PUB putfloatf(str, x, width, digits) | lead0, trail0, man, exp10, signbit, digits0
|
|
{{
|
|
Convert the floating point value in x to a string of character in standard
|
|
notation in str. digits determines the number of fractional digits used and
|
|
width determines the minimum length of the output string. Leading blanks are
|
|
added to achieve the minimum width.
|
|
}}
|
|
if (digits < 0)
|
|
digits := 6
|
|
signbit := tofloat10(x, @man, @exp10)
|
|
digits0 := numdigits(man, @lead0) + exp10
|
|
if (digits0 > 0)
|
|
width -= digits0
|
|
digits0 += digits
|
|
if (digits0 > 8)
|
|
digits0 := 8
|
|
exp10 += round10(digits0, @man) + digits0 - 1
|
|
if (digits0 < 0)
|
|
digits0 := 0
|
|
elseif (digits0 == 0 and man == 1 and digits > 0)
|
|
digits0 := 1
|
|
lead0 := digits - digits0
|
|
trail0 := digits - digits0 + exp10 + 1
|
|
width -= signbit + digits - (lead0 => 0) + 1
|
|
repeat while (width-- > 0)
|
|
byte[str++] := " "
|
|
if (signbit)
|
|
byte[str++] := "-"
|
|
if (lead0 => 0)
|
|
byte[str++] := "0"
|
|
if (lead0 > 0)
|
|
byte[str++] := "."
|
|
repeat while (lead0-- > 0)
|
|
byte[str++] := "0"
|
|
if (digits0 > 0)
|
|
str := utoa10(man, str, exp10 + 1)
|
|
exp10 -= digits0 - 1
|
|
repeat while (trail0-- > 0)
|
|
if (exp10-- == 0)
|
|
byte[str++] := "."
|
|
byte[str++] := "0"
|
|
byte[str] := 0
|
|
return str
|
|
|
|
PUB strtofloat(pstr) | value, exp10, exp10a, signbit, mode, char, esignbit, str
|
|
{{
|
|
Convert the string of characters pointer to by "pstr" into a floating point
|
|
value. The input can be in either standard or scientific notation. Leading
|
|
blanks are ignored. The string pointed to by "pstr" is updated to the last
|
|
character postioned that caused processing to be completed.
|
|
}}
|
|
str := long[pstr]
|
|
esignbit := 0
|
|
mode := 0
|
|
value := 0
|
|
exp10 := 0
|
|
exp10a := 0
|
|
signbit := 0
|
|
repeat
|
|
char := byte[str++]
|
|
if (char == 0)
|
|
quit
|
|
case mode
|
|
0:
|
|
case char
|
|
"0".."9": value := char - "0"
|
|
"-" : signbit := 1
|
|
" " : next
|
|
"+": mode := 1
|
|
other:quit
|
|
mode := 1
|
|
1 :
|
|
case char
|
|
"0".."9":
|
|
if (value =< 200_000_000)
|
|
value := (value * 10) + char - "0"
|
|
else
|
|
exp10++
|
|
".": mode := 2
|
|
"e", "E": mode := 3
|
|
other: quit
|
|
2:
|
|
case char
|
|
"0".."9":
|
|
if (value =< 200_000_000)
|
|
value := (value * 10) + char - "0"
|
|
exp10--
|
|
"e", "E": mode := 3
|
|
other: quit
|
|
3:
|
|
case char
|
|
"0".."9": exp10a := char - "0"
|
|
"-" : esignbit := 1
|
|
"+": mode := 4
|
|
other:quit
|
|
mode := 4
|
|
4:
|
|
case char
|
|
"0".."9":exp10a := (exp10a * 10) + char - "0"
|
|
other: quit
|
|
if (esignbit)
|
|
exp10 -= exp10a
|
|
else
|
|
exp10 += exp10a
|
|
long[pstr] := str
|
|
return fromfloat10(value, exp10, signbit)
|
|
|
|
DAT
|
|
{{
|
|
|
|
________________________
|
|
These tables of scalers are used to scale a floating point number by a ratio of a
|
|
power of 10 versus a power of 2.
|
|
}}
|
|
''SCALE1 10/16 100/128 1000/1024 10^6/2^20 10^12/2^40 10^24/2^80
|
|
scale1 long 1342177280, 1677721600, 2097152000, 2048000000, 1953125000, 1776356839
|
|
''SCALE2 8/10 64/100 512/1000 2^19/10^6 2^39/10^12 2^79/10^24
|
|
scale2 long 1717986918, 1374389535, 1099511628, 1125899907, 1180591621, 1298074215
|
|
nbits1 byte 4, 7, 10, 20, 40, 80
|
|
nbits2 byte 3, 6, 9, 19, 39, 79
|
|
ndecs byte 1, 2, 3, 6, 12, 24
|
|
|
|
PRI floatloop(man, pexp0, pexp1, step0, step1, scale, pexp2, step2) | i
|
|
{{
|
|
This private routine reduces the value of exp0 toward 0 while increasing the value
|
|
of exp1. This is done in a successive approximation method using the scaling
|
|
table passed in "scale". This routine is used here to convert between a mantissa
|
|
times a power of 2 or 10 to a mantissa times a power of 10 or 2.
|
|
}}
|
|
repeat i from 5 to 0
|
|
if (long[pexp0] => byte[step0][i])
|
|
man := (man ** long[scale][i]) << 1
|
|
long[pexp0] -= byte[step0][i]
|
|
long[pexp1] += byte[step1][i]
|
|
if ((man & $40000000) == 0)
|
|
man <<= 1
|
|
long[pexp2] -= step2
|
|
return man
|
|
|
|
PRI tofloat10(value, pman, pexp10) | exp2, exp10, man
|
|
{{
|
|
This private routine converts from a mantissa times a power of 2 to a mantissa
|
|
times a power of 10.
|
|
}}
|
|
result := value >> 31
|
|
exp2 := ((value >> 23) & 255) - 157
|
|
man := ((value & $007fffff) | $00800000) << 7
|
|
exp10 := 0
|
|
if (exp2 =< 0)
|
|
exp2 := -exp2
|
|
man := floatloop(man, @exp2, @exp10, @nbits1, @ndecs, @scale1, @exp2, -1)
|
|
man >>= exp2
|
|
exp10 := -exp10
|
|
else
|
|
exp2 += 2
|
|
man := floatloop(man, @exp2, @exp10, @nbits2, @ndecs, @scale2, @exp2, 1)
|
|
man >>= 2 - exp2
|
|
long[pman] := man
|
|
long[pexp10] := exp10
|
|
|
|
PRI fromfloat10(man, exp10, signbit) | exp2
|
|
{{
|
|
This private routine converts from a mantissa times a power of 10 to a mantissa
|
|
times a power of two.
|
|
}}
|
|
if (man == 0)
|
|
return 0
|
|
exp2 := 0
|
|
repeat while(man & $40000000) == 0
|
|
man <<= 1
|
|
exp2--
|
|
if (exp10 =< 0)
|
|
exp10 := -exp10
|
|
exp2 := -exp2
|
|
man := floatloop(man, @exp10, @exp2, @ndecs, @nbits2, @scale2, @exp2, -1)
|
|
exp2 := -exp2
|
|
else
|
|
man := floatloop(man, @exp10, @exp2, @ndecs, @nbits1, @scale1, @exp2, 1)
|
|
repeat while(man & $ff000000)
|
|
man >>= 1
|
|
exp2++
|
|
return (signbit << 31) | ((exp2 + 150) << 23) | (man & $007fffff)
|
|
|
|
PRI numdigits(man, pdiv) : numdig | divisor
|
|
{{
|
|
This routine determines the number of decimal digits in the number in man.
|
|
}}
|
|
numdig := 10
|
|
divisor := 1000000000
|
|
repeat while (divisor > man)
|
|
numdig--
|
|
divisor /= 10
|
|
long[pdiv] := divisor
|
|
|
|
PRI round10(digits, pman) : exp10 | numdig, divisor, rounder, man
|
|
{{
|
|
This routine round the number poiinted to by pman to the number of decimal
|
|
digits specified by "digits".
|
|
}}
|
|
man := long[pman]
|
|
exp10 := numdigits(man, @divisor) - digits
|
|
if (digits < 0)
|
|
man := 0
|
|
elseif (digits == 0)
|
|
if (man / divisor => 5)
|
|
man := 1
|
|
exp10++
|
|
elseif (exp10 > 0)
|
|
rounder := 1
|
|
repeat exp10
|
|
rounder *= 10
|
|
man :=(man + (rounder >> 1)) / rounder
|
|
divisor /= rounder
|
|
if (man / divisor > 9)
|
|
man /= 10
|
|
exp10++
|
|
elseif (exp10 < 0)
|
|
repeat 0-exp10
|
|
man *= 10
|
|
long[pman] := man
|
|
|
|
PRI utoa10(number, str, point) | divisor, temp
|
|
{{
|
|
This routine converts the value in "number" to a string of decimal characters
|
|
in "str". A decimal point is added after the character position specified by
|
|
the value in "point".
|
|
}}
|
|
if (number == 0)
|
|
byte[str++] := "0"
|
|
byte[str] := 0
|
|
return str
|
|
divisor := 1_000_000_000
|
|
repeat while (divisor > number)
|
|
divisor /= 10
|
|
repeat while (divisor > 0)
|
|
if (point-- == 0)
|
|
byte[str++] := "."
|
|
temp := number / divisor
|
|
byte[str++] := temp + "0"
|
|
number -= temp * divisor
|
|
divisor /= 10
|
|
byte[str] := 0
|
|
return str
|
|
|
|
{{
|
|
┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
|
│ TERMS OF USE: MIT License │
|
|
├──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
|
|
│Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation │
|
|
│files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, │
|
|
│modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software│
|
|
│is furnished to do so, subject to the following conditions: │
|
|
│ │
|
|
│The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.│
|
|
│ │
|
|
│THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE │
|
|
│WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR │
|
|
│COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, │
|
|
│ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. │
|
|
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
|
}}
|