From 7a3debfd0c15b4b85af3af5a03b12652bfe04aff Mon Sep 17 00:00:00 2001 From: Dave Schmenk Date: Thu, 23 Feb 2023 17:57:11 -0800 Subject: [PATCH] Much better floating point string conversion --- src/inc/fpstr.plh | 1 + src/libsrc/fpstr.pla | 151 +++++++++++++++++++++----------------- src/samplesrc/rpncalc.pla | 16 ++-- 3 files changed, 92 insertions(+), 76 deletions(-) diff --git a/src/inc/fpstr.plh b/src/inc/fpstr.plh index 02eecb1..f642b4d 100644 --- a/src/inc/fpstr.plh +++ b/src/inc/fpstr.plh @@ -6,6 +6,7 @@ const FPSTR_FIXED = 1 // Fixed count of fractional digits const FPSTR_FLOAT = 0 // Floating count of fractional digits const FPSTR_STRIP = 2 // Strip trailing fractional zeros const FPSTR_EXP = 4 // Force exponential format +const FPSTR_FLEX = 8 // Flexible switch to EXP format if over/underflow // // Parse string into decrecord, return SANE conversion output // diff --git a/src/libsrc/fpstr.pla b/src/libsrc/fpstr.pla index 033e271..9c2c24e 100644 --- a/src/libsrc/fpstr.pla +++ b/src/libsrc/fpstr.pla @@ -3,6 +3,7 @@ // include "inc/cmdsys.plh" include "inc/sane.plh" +include "inc/fpstr.plh" // // Structures for DEC2BIN, BIN2DEC // @@ -136,14 +137,15 @@ end // Convert extended FP to string using , return string // export def ext2str(ext, str, intdigits, fracdigits, format) - byte d, i, sigdigits, numdigits - word dp, tens + byte d, numdigits + word istr, dp, tens byte decform[t_decformat] byte decrec[t_decrecord] - numdigits = intdigits + fracdigits - decform:style = format & $01 + numdigits = intdigits + fracdigits + decform:style = format & FPSTR_FIXED decform:digits = decform:style ?? fracdigits :: numdigits + decrec:exp = 0 sane:saveZP() sane:restoreZP(sane:op3FP(FFEXT|FOB2D, @decrec, ext, @decform)) ^(str+1) = decrec.sgn ?? '-' :: ' ' @@ -162,94 +164,109 @@ export def ext2str(ext, str, intdigits, fracdigits, format) return str fin dp = decrec.sig + decrec:exp - if decrec.sig.1 == '0' - // - // Zero with significant fractional digits - // - while decrec.sig <= fracdigits - decrec.sig++ - decrec.sig[decrec.sig] = '0' - loop - decrec:exp = 0 - dp = 1 - fin - sigdigits = decrec.sig - if decrec:exp < 0 and format & $02 - // - // Strip off trailing fractional zeros - // - while sigdigits > dp and decrec.sig[sigdigits] == '0' - sigdigits-- - decrec:exp++ - loop - fin - if -decrec:exp > numdigits or sigdigits + decrec:exp >= (decform:style ?? intdigits :: numdigits) or format & $04 - // - // Convert to exponential format - // - ^(str+2) = decrec.sig.1 - ^(str+3) = '.' - i = 3 - fracdigits = fracdigits - 5 // Replace last four fracdigits with exponent notation - for d = 0 to fracdigits - i++ - ^(str+i) = decrec.sig.2[d] - next + if format & FPSTR_EXP + if format & FPSTR_STRIP + // + // Strip off trailing fractional zeros + // + while decrec.sig > 1 and decrec.sig[decrec.sig] == '0' + decrec.sig-- + decrec:exp++ + loop + fin // // Copy over all significant digits // - if ^(str+i) == '.'; i--; fin - i++ - ^(str+i) = 'E' - i++ + ^(str+2) = decrec.sig.1 + ^(str+3) = '.' + istr = str + 3 + for d = 2 to decrec.sig + istr++ + ^istr = decrec.sig[d] + next + if ^istr == '.'; istr--; fin + // + // Print exponent as 4 digits with leading zeros + // + istr++ + ^istr = 'E' + istr++ dp-- if dp < 0 - ^(str+i) = '-' + ^istr = '-' dp = -dp else - ^(str+i) = '+' - fin - // - // Pretty output the exponent (preceding zero for values less than 10) - // - if dp < 100 - tens = 10 - else - tens = 10000 - while !(dp / tens) - tens = tens / 10 - loop + ^istr = '+' fin + tens = 1000 while tens - i++ - ^(str+i) = (dp / tens) + '0' + istr++ + ^istr = (dp / tens) + '0' dp = dp % tens tens = tens / 10 loop else + if format & FPSTR_STRIP and decrec:exp < 0 + // + // Strip off trailing fractional zeros + // + while decrec.sig > dp and decrec.sig[decrec.sig] == '0' + decrec.sig-- + decrec:exp++ + loop + fin + if decrec:sig == 1 | '0'<<8 + // + // Case of zero or underflow + // + if decrec:exp == 0 + // + // Zero + // + if format & FPSTR_FIXED + // + // Add trailing fractional zeros + // + dp = 1 - fracdigits + fin + elsif format & FPSTR_FLEX + // + // Underflow + // + dp = -fracdigits + fin + fin + if format & FPSTR_FLEX and (dp <= -fracdigits or dp >= (format & FPSTR_FIXED ?? intdigits :: numdigits)) + // + // Print as exponent if over/underflow fixed digits + // + if numdigits < 8; numdigits = 8; fin + return ext2str(ext, str, 1, numdigits - 8, FPSTR_EXP | (format & FPSTR_STRIP)) + fin // // Convert as floating point // - i = 1 if dp <= 0 *(str+2) = '0'|('.'<<8) - i = 3 + istr = str + 3 while dp < 0 dp++ - i++ - ^(str+i) = '0' + istr++ + ^istr = '0' loop + else + istr = str + 1 fin - for d = 1 to sigdigits - i++ - ^(str+i) = decrec.sig[d] + for d = 1 to decrec.sig + istr++ + ^istr = decrec.sig[d] if d == dp - i++ - ^(str+i) = '.' + istr++ + ^istr = '.' fin next - if ^(str+i) == '.'; i--; fin + if ^istr == '.'; istr--; fin fin - ^str = i + ^str = istr - str return str end diff --git a/src/samplesrc/rpncalc.pla b/src/samplesrc/rpncalc.pla index c5ddf13..7249261 100644 --- a/src/samplesrc/rpncalc.pla +++ b/src/samplesrc/rpncalc.pla @@ -37,7 +37,7 @@ byte inputStr[32] = "" // Display format state // byte displayFix = 6 -byte displayInt = displayWidth - 7 // - displayFix - 1 +byte displayInt = displayWidth - 8 // // Store/load memory // @@ -81,8 +81,6 @@ byte[t_keypad] = '0', 3, 16, "[0]" word = @digitKey byte[t_keypad] = '.', 7, 16, "[.]" word = @pointKey -byte[t_keypad] = 'E', 3, 16, "[0]" -word = @digitKey byte[t_keypad] = 'X', 11, 16, "[X]" word = @dropKey byte[t_keypad] = '+', 15, 16, "[+]" @@ -109,7 +107,7 @@ byte[t_keypad] = '^', 30, 14, "[X(^)Y]" word = @elemsKey byte[t_keypad] = 'L', 30, 16, "[(L)G2]" word = @elemsKey -byte[t_keypad] = 'E', 30, 18, "[(P)^X]" +byte[t_keypad] = 'E', 30, 18, "[(E)^X]" word = @elemsKey byte[t_keypad] = 'N', 30, 20, "[L(N)X]" word = @elemsKey @@ -154,7 +152,7 @@ def showStack#0 byte strFP[displayWidth+1] for s = 0 to 3 - fpu:storStr(@strFP, displayInt, displayFix, FPSTR_FIXED, s) + fpu:storStr(@strFP, displayInt, displayFix, FPSTR_FIXED|FPSTR_FLEX, s) conio:gotoxy(4, 5 - s) repc(displayWidth - strFP - 1, ' ') puts(@strFP) @@ -165,7 +163,7 @@ def showMem#0 byte strFP[displayWidth+1] for m = 0 to 9 - ext2str(@memory[m*t_fpureg], @strFP, displayInt, displayFix, FPSTR_FIXED) + ext2str(@memory[m*t_fpureg], @strFP, displayInt, displayFix, FPSTR_FIXED|FPSTR_FLEX) conio:gotoxy(23, 2 + m) repc(displayWidth - strFP - 1, ' ') puts(@strFP) @@ -254,7 +252,7 @@ def delKey(pkey)#0 showInput end def dropKey(pkey)#0 - fpu:pullStr(@inputStr, displayInt, displayFix, FPSTR_STRIP|FPSTR_FLOAT) + fpu:pullStr(@inputStr, displayInt, displayFix, FPSTR_STRIP|FPSTR_FLOAT|FPSTR_FLEX) if inputStr.1 == ' ' inputStr-- memcpy(@inputStr.1, @inputStr.2, inputStr) @@ -263,7 +261,7 @@ def dropKey(pkey)#0 showStack end def copyKey(pkey)#0 - fpu:storStr(@inputStr, displayInt, displayFix, FPSTR_STRIP|FPSTR_FLOAT, X_REG) + fpu:storStr(@inputStr, displayInt, displayFix, FPSTR_STRIP|FPSTR_FLOAT|FPSTR_FLEX, X_REG) if inputStr.1 == ' ' inputStr-- memcpy(@inputStr.1, @inputStr.2, inputStr) @@ -452,7 +450,7 @@ initInput showStack showMem showInput -showStatus("Version 0.6") +showStatus("Version 0.7") inputKey conio:gotoxy(0, 22) done