Did you ever have a project that required a second to be complete? Then the second project required a third? Well, this a third. Finishing will allow me to to get back to the second.
SI is acronym for International System of units. The letter order of SI is because in French the name of the system is Système International d'unités. Units are second, metre (meter), kilogram, etcetera. There are also derived units like Hertz, Watt and Newton, and more.
The function presented here formats the significand (numeric part) into groups of 3 powers of 10, and adds a prefix letter. It is called a prefix because it is before the unit. The user appends the unit's name or abreviation. See here (in new window or tab) for SI prefix list. SI prefixes for hecto (h), deca (da), deci (d) and centi (c) are not supported. The exponents of ten they represent are not evenly divisable by 3.
For example, there is a signal of 10234000 Hertz. SI prefix formatted it is written, printed or displayed 10.234 MHz.
Jump to source code -
Include file
Code to compile SLL
PBCC demo
PBWin demo
Download compiled SLL
in ZIP file (release 20221209).
Download compiled demo
programs in a zip file (release 20221209). You don't need a compiler to try
either the GUI or console application.
------ Unmodified E Division and MOD, then modified ------ Quotient Remainder Exponent Quotient Remainder Raw Of \ 3 Raw Of \ 3 Raw Modified With Modified Also Exponent Exponent Exponent If Negative Exponent Modified 6 2 0 6 2 0 5 1 2 5 1 2 4 1 1 4 1 1 3 1 0 3 1 0 2 0 <--§ 2 2 0 2 1 0 <--§ 1 1 0 1 0 0 <--§ 0 <--◊ 0 0 0 -1 0 <--§ -1 <--‡ -3 -1 2 -2 0 <--§ -2 <--‡ -4 -1 1 -3 -1 <--† 0 -5 -1 0 -4 -1 <--† -1 -6 -2 2 -5 -1 <--† -2 -7 -2 1 -6 -2 0 -8 -2 0 (footnote markers edited in)§ - Quotient of exponents 2 down to -2 all 0; not unique to exponents 0, 1 and 2 which do not get a prefix, and -3, -2 and -1 which should have prefix of "m" for milli.
At the end of the function are appending the prefix to SignificandStr and out of range GOTO code.
Include file has #LINK for SLL, and remarked out DECLARE
'file SI_PrefixFormat.inc 'file SI_PrefixFormat.inc 'Not really needed for one #LINK line. It has to be somewhere. ' #link "SI_PrefixFormat.sll" 'adjust path as needed ' '------------------------------------------------------------------------------- 'for info if you only have compiled SLL - ' 'declare function SI_PrefixFormat alias "SI_PrefixFormat" _ ' (byref NumToFormat as ext, _ ' opt byval DigitsOut as long, _ ' opt byval DP_Align as long, _ ' opt byval No3DigGrps as long) as wstring 'DigitsOut allows 3 to 18, default 6. '··3 minimum for hundreds in any prefix. '····option not used or 0 sets default. '····1, 2 or negative are corrected to 3. '··18 is maximum for Extended floating point type. '····greater than 18 is corrected to 18. ' 'DP_Align, not aligned is default. '··option not used or 0 for left aligned. '··non 0 (suggest -1) for left padded with spaces for decimal points alignment. '··(for best results use non-proportional (fixed width) font) ' '############################################################################### 'A MACRO for aligning on the decimal point posted elsewhere on PB forum. It 'works with either proportional or non-proportional fonts. If you use that 'MACRO, or similar code, do not use DP_Align option of this function. ' 'No3DigGrps, 3 digit groups (with thousands separators) is default. '··option not used or 0 for default. '··non 0 (suggest -1) for no separation. '------------------------------------------------------------------------------- 'If you'd rather have a DLL than SLL, or pasting the function into your code; 'comment the #LINK line, uncomment the whole DECLARE. In source file change '#COMPILE SLL to #COMPILE DLL, and COMMON to EXPORT in FUNCTION definition, 'add ALIAS.
I added the thousands separation to the BASIC code first, when that was working how I wanted I rewrote in assembly. The assembly source code is longer than the BASIC, but compiled to half the size!
'release 20221209, added prefixes Q, R, r and q. ' 'Now thousands separation applied to fraction part of value with spaces by 'default per the General Conference on Weights and Measures. This can optionally 'be disabled. The significand (integer part) does not need thousands separation 'because it is already limited to 1 to 999 in order to use the prefix. ' 'The units, or their abreviations, should be appended directly on the resulting 'wide string. (Byte oriented strings should only used for DIBs, numeric types 'and UTF-8 over a network.) ' 'Description of optional parameters in INCLUDE file in following code block. ' 'Copyleft 2022 by Dale Yarker; do what you want with this code except claim it, 'or sell it, as yours. No warranty of any kind. #compile sll "SI_PrefixFormat.sll" #dim all ' function SI_PrefixFormat(byval NumToFormat as ext, _ opt byval DigitsOut as long, _ opt byval DP_Align as long, _ opt byval No3DigitGrps as long) common as wstring #register none local NumInStr, NumOutStr as wstring local pNumInChar, pNumOutChar, pLastInChar, pLenNumOutStr as dword local NumIsNeg, ExpntIsNeg, RemainBytes as long local E as long '1st as exponent of normatized number in, then it 'is exponent integer divided by 3. local E_Mod3 as long 'Remainder of exponent integer divided by 3. '------------------------------------------- Check/Set number of DigitsOut. -- ! push eax ! mov eax, DigitsOut ! cmp eax, 0& 'optional parameter not used or set to 0 ! jne DigitsOutNotDefault 'go check minimum ! mov DigitsOut, 6& 'set default ! jmp DigitsOutDone DigitsOutNotDefault: ! cmp eax, 3& 'non-valid 1, 2 or negative ! jge DigitsOutNotLTMin 'go check maximum ! mov DigitsOut, 3& 'set minimum ! jmp DigitsOutDone DigitsOutNotLTMin: ! cmp eax, 18& 'non-valid greater than 18 ! jle DigitsOutDone 'not above max ! mov DigitsOut, 18& 'set maximum DigitsOutDone: ! pop eax '------------------- Binary to string; get last digit, current digit and E. -- 'extended float input to string of integer plus exponent NumInStr = format$(NumToFormat, string$(DigitsOut, "#") + "e-##") ' 'Exponent of input as integer E = val(NumInStr, instr(-1, NumInStr, "e") + 1) ' pNumInChar = strptr(NumInStr) NumOutStr = string$(30, $$nul) pNumOutChar = strptr(NumOutStr) ' ? ' ? E, NumInStr ' exit function ' ! push eax ! push ebx ! push ecx ! push edx ! push edi ! push esi '------ Set variabes, leave in register if possible, or Format zero result. -- 'calculate pointer to last digit of input string ! mov ebx, DigitsOut ! sal ebx, 1??? ! mov ecx, pNumInChar ! add ebx, ecx ! mov pLastInChar, ebx ' ! sal pLastInChar, 1& 'number characters times 2 for number of bytes ! sub pLastInChar, 2& 'result character pointer to register and calculate pointer to 'pointer to byte length of result string ! mov edi, pNumOutChar ! mov esi, edi ! sub esi, 4& 'is pLenNumOutStr 'Check for negative ! cmp word ptr [ecx], &h002d?? '"-" ! je Sgnfcnd_Is_Neg 'can't be 0 if negative 'Check "1" or greater than ! cmp word ptr [ecx], &h0031?? '"1" ! jae Sgnfcnd_NotZero 'CHeck DP_Align ! cmp DP_Align, 0& ! jne SgnfcndIsZeroIsDPAlgn 'SgnfcndIsZeroNotDPAlign ! mov dword ptr [edi], &h002E0030??? 'zero dp ! add edi, 4??? ! mov word ptr [edi], &h0030?? 'zero ! mov dword ptr [esi], &h00000006??? '6 to pLenNumOutStr ! jmp FunctionDone SgnfcndIsZeroIsDPAlgn: ! mov dword ptr [edi], &h00200020??? 'space space ! add edi, 4??? ! mov dword ptr [edi], &h00300020??? 'space zero ! add edi, 4??? ! mov dword ptr [edi], &h0030002E??? 'dp zero ! mov dword ptr [esi], &h00000012??? '12 to pLenNumOutStr ! jmp FunctionDone Sgnfcnd_Is_Neg: ! mov NumIsNeg, -1& Sgnfcnd_NotZero: 'non-zero to here, positive skips past Sgnfcnd_Is_Neg '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ only EBX available ~~~~ '-------------- Calc E \ 3 and E MOD 3, both modified for negative E MOD 3. -- ! mov eax, E ! add eax, DigitsOut ! sub eax, 1& ! bt eax, 31??? 'bit 31 can only be set if LONG is negative ! jnc E_IsPositive1 ! mov ExpntIsNeg, -1& ! mov edx, -1& 'make edx upper part of 64 bit 2s compliment to eax's lower ! sub eax, 2& ' ! jmp DoDivide E_IsPositive1: ! xor edx, edx 'edx to 0 DoDivide: ! mov ebx, 3& 'divisor ! idiv ebx ! cmp ExpntIsNeg, 0& ! je E_IsPositive2 ! add edx, 2& E_IsPositive2: '-------------------- Use E MOD 3 for dp align, and to place decimal point. -- '. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . is tens . . ! cmp edx, 1& ! jg HundredsInteger ! jl UnitsInteger 'Tens Padding and minus sign ! cmp DP_Align, 0& ! je TensNoAlignPad 'Tens Align Pad ! cmp NumIsNeg, 0& ! jne TensAlignNegPad 'TensAlignPosPad ! mov dword ptr [edi], &h00200020??? 'space space ! add edi, 4& 'OutChar ptr adjust ! mov dword ptr [esi], 4& 'Out Len set ! jmp TensIntegerDigits TensAlignNegPad: ! mov dword ptr [edi], &h002D0020??? 'space minus ! add ecx, 2& 'InChar ptr adjust ! add edi, 4& 'OutChar ptr adjust ! mov dword ptr [esi], 4& 'Out Len set ! jmp TensIntegerDigits TensNoAlignPad: ! cmp NumIsNeg, 0& ! jne TensNoAlignPadNeg 'TensNoAlignPosPad ! mov dword ptr [esi], 0& 'Out Len set ! jmp TensIntegerDigits TensNoAlignPadNeg: ! mov word ptr [edi], &h002D?? 'minus ! add ecx, 2& 'InChar ptr adjust ! add edi, 2& 'OutChar ptr adjust ! mov dword ptr [esi], 2& 'Out Len set TensIntegerDigits: ! mov ebx, dword ptr [ecx] '2 digits InChar to register ! mov dword ptr [edi], ebx '2 digits register to OutChar ! add ecx, 4& 'InChar ptr adjust ! add edi, 4& 'OutChar ptr adjust ! add dword ptr [esi], 4& 'Out Len adjust ! jmp DoDecimalPoint '· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · is hundreds · · HundredsInteger: 'Hundreds Padding and minus sign ! cmp DP_Align, 0& ! je HundredsNoAlignPad 'Hundreds Align Pad ! cmp NumIsNeg, 0& ! jne HundredsAlignPadNeg 'HundredsAlignPadPos ! mov word ptr [edi], &h0020?? 'space ! add edi, 2??? ! mov dword ptr [esi], 2& ! jmp HundredsIntegerDigits HundredsAlignPadNeg: ! mov word ptr [edi], &h002D?? 'minus ! add ecx, 2??? ! add edi, 2??? ! mov dword ptr [esi], 2& ! jmp HundredsIntegerDigits HundredsNoAlignPad: ! cmp NumIsNeg, 0& ! jne HundredsNoAlignPadNeg 'HundredsnoAlignPadPos ! mov dword ptr [esi], 0& 'set length of OutStr to 0 ! jmp HundredsIntegerDigits HundredsNoAlignPadNeg: ! mov word ptr [edi], &h002D?? 'minus ! add ecx, 2??? ! add edi, 2??? ! mov dword ptr [esi], 2& '"fall" to HundredsIntegerDigits HundredsIntegerDigits: ! mov ebx, dword ptr [ecx] ! mov dword ptr [edi], ebx '1st and 2nd digits ! add ecx, 4& ! add edi, 4& ! mov bx, word ptr [ecx] ! mov word ptr [edi], bx '3rd digit ! add ecx, 2& ! add edi, 2? ! add dword ptr [esi], 6& ! cmp DigitsOut, 3& ! jg DoDecimalPoint ! je DoPrefix 'Error ! mov dword ptr [esi], 10& ! mov edi, esi ! add edi, 4??? ! mov dword ptr [edi], &h00520045??? 'E R ! add edi, 4??? ! mov dword ptr [edi], &h004F0052??? 'R O ! add edi, 4??? ! mov dword ptr [edi], &h00000052??? 'R nul ! jmp FunctionDone '· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · is units · · UnitsInteger: ! cmp DP_Align, 0& ! je UnitsNoAlignPad 'UnitsAlignPad ! cmp NumIsNeg, 0& ! jne UnitsAlignPadNeg 'UnitsAlignPadPos ! mov dword ptr [edi], &h00200020??? 'space space ! add edi, 4??? ! mov word ptr [edi], &h0020?? 'space ! add edi, 2?? ! mov dword ptr [esi], 6& ! jmp UnitsIntegerDigits UnitsAlignPadNeg: ! mov dword ptr [edi], &h00200020??? 'space space ! add edi, 4??? ! mov word ptr [edi], &h002D?? 'minus ! add ecx, 2?? ! add edi, 2?? ! mov dword ptr [esi], 6& ! jmp UnitsIntegerDigits UnitsNoAlignPad: ! cmp NumIsNeg, 0& ! jne UnitsNoAlignPadNeg 'UnitsNoAlignPadPos ! mov dword ptr [esi], 0& ! jmp UnitsIntegerDigits UnitsNoAlignPadNeg: ! mov word ptr [edi], &h002D?? ! add ecx, 2?? ! add edi, 2?? ! mov dword ptr [esi], 2& '"fall" to UnitsIntegerDigits UnitsIntegerDigits: ! mov bx, word ptr [ecx] 'InChar to register ! mov word ptr [edi], bx ! add ecx, 2??? ! add edi, 2??? ! add dword ptr [esi], 2& '"fall" to DoDecimalPoint '· · · · · · · · · · · · · · · · · · · · · · · · · · append decimal point · · DoDecimalPoint: ! mov word ptr [edi], &h002E?? 'decimal point ! add edi, 2??? ! add dword ptr [esi], 2& '"fall" to FractionDigits '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EDX now available ~~~~ '---------------------------- Fraction digits - continuous or 3 digit groups - FractionDigits: ! mov ebx, pLastInChar ! sub ebx, ecx ! add ebx, 2??? 'Remaining Bytes ''' ! cmp No3DigitGrps, 0& ! jne FractionGrpsNoTop FractionGrpsYesTop: ! cmp ebx, 6??? ! jg FractionGrpsYesGT6 ! jl FractionGrpsYesLT6 'FractionGrpsYesET6 ! mov edx, dword ptr [ecx] '2 InChars of last 3 char group to EDX ! mov dword ptr [edi], edx 'EDX to OutChars ! add ecx, 4??? 'adjust ECX point 3rd InChar of group ! add edi, 4??? 'adjust EDI point 3rd OutChar of group ! mov dx, word ptr [ecx] '3rd InChar to DX. Is last, no adjust ECX ! mov word ptr [edi], dx 'DX to OutChar ! add edi, 2??? 'adjust EDI point space by DoPrefix ! add dword ptr [esi], 6& 'adjust LEN OutChars by appended bytes ! jmp DoPrefix FractionGrpsYesGT6: ! mov edx, dword ptr [ecx] '1st and 2nd InChars to EDX ! mov dword ptr [edi], edx 'EDX to OutChars ! add ecx, 4??? 'adjust ECX point to 3rd InChar of group ! add edi, 4??? 'adjust EDI point to 3rd OutChar of group ! mov dx, word ptr [ecx] '3rd InChar to DX ! mov word ptr [edi], dx 'DX to OutChar ! add ecx, 2??? 'adjust ECX point 1st InChar next of group ! add edi, 2??? 'adjust EDI point to group separator ! mov word ptr [edi], &h0020??? 'space ! add edi, 2??? 'adjust EDI point 1st OutChar next of group ! add dword ptr [esi], 8& 'adjust LEN OutChars by appended bytes ! sub ebx, 6??? 'reduce remaining bytes of InChar by 6 ! jmp FractionGrpsYesTop FractionGrpsYesLT6: ! cmp ebx, 4??? ! je FractionGrpsBothET4 'je ! jl FractionGrpsBothLT4 FractionGrpsNoTop: ! cmp ebx, 4??? ! je FractionGrpsBothET4 ! jl FractionGrpsBothLT4 'FractionGrpsNoGT4: ! mov edx, dword ptr [ecx] ! mov dword ptr [edi], edx ! add ecx, 4??? ! add edi, 4??? ! add dword ptr [esi], 4& ! sub ebx, 4??? '6 ! jmp FractionGrpsNoTop 'these the same for 3 digit groups and ungrouped '-------------------------------------------------------- FractionGrpsBothET4: ! mov edx, dword ptr [ecx] '2 InChars to EDX ! mov dword ptr [edi], edx 'EDX to OutChar. Is last, no adjust ECX ! add edi, 4??? 'adjust EDI point space by DoPrefix ! add dword ptr [esi], 4& 'adjust LEN OutChars by appended bytes ! jmp DoPrefix FractionGrpsBothLT4: ! mov dx, word ptr [ecx] ! mov word ptr [edi], dx ! add edi, 2??? ! add dword ptr [esi], 2& ! jmp DoPrefix '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ EBX, ECX EDX now available ~~~~ '------------------------------------------- Use E \ 3 for prefix selection -- DoPrefix: ! cmp eax, 0& ! jg PrefixGT0 ! jl PrefixLt0 'PrefixET0 ! mov word ptr [edi], &h0020?? 'space for no prefix unit symbol ! add dword ptr [esi], 2& ! jmp FunctionDone PrefixGT0: ! cmp eax, 4& ! jg PrefixGT4 ! jl PrefixLt4 'PrefixET4 ! mov dword ptr [edi], &h00540020??? 'space T ! jmp PrefixLenNumOutStr PrefixGT4: ! cmp eax, 8& ! jg PrefixGT8 ! jl PrefixLT8 'PrefixET8 ! mov dword ptr [edi], &h00590020??? 'space Y ! jmp PrefixLenNumOutStr PrefixGT8: ! cmp eax, 10& ! jg PrefixGT10 ! jl PrefixLT10 'PrefixET10: ! mov dword ptr [edi], &h00510020??? 'space Q ! jmp PrefixLenNumOutStr PrefixGT10: ! jmp OutOfRange PrefixLT10: ! mov dword ptr [edi], &h00520020??? 'space R ! jmp PrefixLenNumOutStr PrefixLt8: ! cmp eax, 6& ! jg PrefixGT6 ! jl PrefixLT6 'PrefixET6 ! mov dword ptr [edi], &h00450020??? 'space E ! jmp PrefixLenNumOutStr PrefixGT6: ! mov dword ptr [edi], &h005A0020??? 'space Z ! jmp PrefixLenNumOutStr PrefixLT6: ! mov dword ptr [edi], &h00500020??? 'space P ! jmp PrefixLenNumOutStr PrefixLT4: ! cmp eax, 2& ! jg PrefixGT2 ! jl PrefixLT2 'PrefixET2 ! mov dword ptr [edi], &h004D0020??? 'space M ! jmp PrefixLenNumOutStr PrefixGT2: ! mov dword ptr [edi], &h00470020??? 'space G ! jmp PrefixLenNumOutStr PrefixLT2: ! mov dword ptr [edi], &h006B0020??? 'space k ! jmp PrefixLenNumOutStr PrefixLT0: ! cmp eax, -4& ! jl PrefixLTm4 ! jg PrefixGTm4 'PrefixETm4 ! mov dword ptr [edi], &h00700020??? 'space p ! jmp PrefixLenNumOutStr PrefixLTm4: ! cmp eax, -8& ! jl PrefixLTm8 ! jg PrefixGTm8 'PrefixETm8 ! mov dword ptr [edi], &h00790020??? 'space y ! jmp PrefixLenNumOutStr PrefixLTm8: ! cmp eax, -10& ' ! jl PrefixLTm10 ! jg PrefixGTm10 'PrefixETm10 ! mov dword ptr [edi], &h00710020??? 'space q ! jmp PrefixLenNumOutStr PrefixLTm10: ! jmp OutOfRange PrefixGTm10: ! mov dword ptr [edi], &h00720020??? 'space r ! jmp PrefixLenNumOutStr PrefixGTm8: ! cmp eax, -6& ! jl PrefixLTm6 ! jg PrefixGTm6 'PrefixETm6 ! mov dword ptr [edi], &h00610020??? 'space a ! jmp PrefixLenNumOutStr PrefixLTm6: ! mov dword ptr [edi], &h007A0020??? 'space z ! jmp PrefixLenNumOutStr PrefixGTm6: ! mov dword ptr [edi], &h00660020??? 'space f ! jmp PrefixLenNumOutStr PrefixGTm4: ! cmp eax, -2& ! jl PrefixLTm2 ! jg PrefixGTm2 'PrefixETm2 ! mov dword ptr [edi], &h00B50020??? 'space µ ! jmp PrefixLenNumOutStr PrefixLTm2: ! mov dword ptr [edi], &h006E0020??? 'space n ! jmp PrefixLenNumOutStr PrefixGTm2: ! mov dword ptr [edi], &h006D0020??? 'space m '"fall" to PrefixLenNumOutStr PrefixLenNumOutStr: ! add dword ptr [esi], 4& FunctionDone: ! pop esi ! pop edi ! pop edx ! pop ecx ! pop ebx ! pop eax function = NumOutStr ' exit function '=============================================================== ' OutOfRange: ! pop esi '(if here, never gets to POPs above) ! pop edi ! pop edx ! pop ecx ! pop ebx ! pop eax function = "Out of prefix range."$$ end function
The console demo used for testing during coding.
'PBCC6 application to demonstrate SI_PrefixFormat function. 'Release 20221209. 'file demoSIFormatCC.bas 'Is "brute force", but checks units, tens and hundreds, and rounded to 1000 'from lower for each prefix. Also align decimal points and thousands separation. 'Copyleft 2022 by Dale Yarker; do what you want with this code except claim it 'or sell it as yours. No warranty of any kind. #compile exe #dim all #break on #include "SI_PrefixFormat.inc" function pbmain () as long con.caption$ = "SI with prefix formating for PBCC demo" con.print "### Exponent greater than or equal to zero, and number equals " + _ "zero. ###" con.print 7.99999*10^33##; " " SI_PrefixFormat(7.99999*10^33##, 4, 0) con.print " 9.9999999999999999 * 10^32##"; " " _ SI_PrefixFormat(9.9999999999999999 * 10^32##, 4, -1); _ " FORMAT$() rounded to OOR" con.print "------------------------- Prefixes added by SI in 2022 -----------------------" con.print "Q, DigitsOut MOD3=1, not decimal aligned, thousand no separation" con.print SI_PrefixFormat(1.23456789432 * 10^32##, 5, 0, -1) con.print SI_PrefixFormat(1.23456789432 * 10^31##, 5, 0, -1) con.print SI_PrefixFormat(1.23456789432 * 10^30##, 5, 0, -1) con.print SI_PrefixFormat(9.9999999999999999 * 10^29##, 5, 0, -1), _ "rounded from R to Q" con.print "R, DigitsOut MOD3=0, decimal aligned, thousand separation" con.print SI_PrefixFormat(1.23456789432 * 10^29##, 5, -1) con.print SI_PrefixFormat(1.23456789432 * 10^28##, 5, -1) con.print SI_PrefixFormat(1.23456789432 * 10^27##, 5, -1) con.print SI_PrefixFormat(9.9999999999999999 * 10^26##, 5, -1), _ "rounded from Y to R" con.print "------------------------------------------------------------------------------" con.print "Y, DigitsOut MOD3=2, decimal aligned, thousand separation" con.print SI_PrefixFormat(1.23456789432 * 10^26##, 11, -1, 0) ' #if 0 con.print SI_PrefixFormat(1.23456789432 * 10^25##, 11, -1, 0) con.print SI_PrefixFormat(1.23456789432 * 10^24##, 11, -1, 0) con.print SI_PrefixFormat(9.9999999999999999 * 10^23##, 4, -1, 0), _ "rounded from Z to Y" con.print con.print "Z, DigitsOut MOD3=1, decimal aligned, thousand separation" con.print SI_PrefixFormat(1.23456789432 * 10^23##, 10, -1, 0) con.print SI_PrefixFormat(1.23456789432 * 10^22##, 10, -1, 0) con.print SI_PrefixFormat(1.23456789432 * 10^21##, 10, -1, 0) con.print SI_PrefixFormat(9.9999999999999999 * 10^20##, 4&, -1, 0), _ "rounded from E to Z" con.print con.print "E DigitsOut MOD3=0, decimal aligned, thousand separation" con.print SI_PrefixFormat(1.23456789432 * 10^20##, 9, -1, 0) con.print SI_PrefixFormat(1.23456789432 * 10^19##, 9, -1, 0) con.print SI_PrefixFormat(1.23456789432 * 10^18##, 9, -1, 0) con.print SI_PrefixFormat(9.9999999999999999 * 10^17##, 4&, -1&, 0), _ "rounded from P to E" con.print "------------------------------------------------------------------------------" con.print "P, DigitsOut MOD3=2, not decimal aligned, thousand separation" con.print SI_PrefixFormat(1.23456722 * 10^17##, 8, 0, 0) con.print SI_PrefixFormat(1.23456722 * 10^16##, 8, 0, 0) con.print SI_PrefixFormat(1.23456722 * 10^15##, 8, 0, 0) con.print SI_PrefixFormat(9.9999999999999999 * 10^14##, 4, 0, 0), _ "rounded from T to P" con.print con.print "T, DigitsOut MOD3=1, not decimal aligned, thousand separation" con.print SI_PrefixFormat(1.23456722 * 10^14##, 7, 0, 0) con.print SI_PrefixFormat(1.23456722 * 10^13##, 7, 0, 0) con.print SI_PrefixFormat(1.23456722 * 10^12##, 7, 0, 0) con.print SI_PrefixFormat(9.9999999999999999 * 10^11##, 4, 0), _ "rounded from G to T con.print con.print "G, DigitsOut MOD3=0, not decimal aligned, thousand separation" con.print SI_PrefixFormat(1.23456722 * 10^11##, 6, 0, 0) con.print SI_PrefixFormat(1.23456722 * 10^10##, 6, 0, 0) con.print SI_PrefixFormat(1.23456722 * 10^9##, 6, 0, 0) con.print SI_PrefixFormat(9.9999999999999999 * 10^8##, 4&, 0), _ "rounded from M to G" con.print "------------------------------------------------------------------------------" con.print "M, negative, DigitsOut MOD2=1, decimal aligned, no thousand separation" con.print SI_PrefixFormat(-1.23456722 * 10^8##, 7, -1, -1) con.print SI_PrefixFormat(-1.23456722 * 10^7##, 7, -1, -1) con.print SI_PrefixFormat(-1.23456722 * 10^6##, 7, -1, -1) con.print SI_PrefixFormat(-9.9999999999999999 * 10^5##, 7, -1, -1), _ "rounded from k to M" con.print con.print "k, negative, DigitsOut MOD2=0, decimal aligned, no thousand separation" con.print SI_PrefixFormat(-1.23456722 * 10^5##, 6, -1, -1) con.print SI_PrefixFormat(-1.23456722 * 10^4##, 6, -1, -1) con.print SI_PrefixFormat(-1.23456722 * 10^3##, 6, -1, -1) con.print SI_PrefixFormat(-9.9999999999999999 * 10^2##, 4&, -1&), _ "rounded from none to k" con.print "------------------------------------------------------------------------------" con.print "no prefix, 3 DigitsOut, " con.print SI_PrefixFormat(1.2345 * 10^2##, 3, -1, -1), "no decimal point" con.print SI_PrefixFormat(1.2345 * 10^1##, 3, -1, 0), " con.print SI_PrefixFormat(9.9999999999999999##, 3, -1), "rounded from 9.99 to 10" con.print SI_PrefixFormat(1.2345##, 3, -1, 0) con.print con.print SI_PrefixFormat(0.0##, 5, -1, 0) con.print SI_PrefixFormat(0.0##, 4, 0, -1) con.print SI_PrefixFormat(9.9999999999999999 * 10^-1##, 4, -1), _ "rounded from m to none" con.print string$$(79, "=") '------------------------------------------------- con.print "Exponent less than zero." con.print con.print "m, negative, DigitsOut MOD3=0, decimal aligned, thousand separation" con.print SI_PrefixFormat(-1.2345678998765432 * 10^-1, 18, -1) con.print SI_PrefixFormat(-1.2345678998765432 * 10^-2, 18, -1) con.print SI_PrefixFormat(-1.2345678998765432 * 10^-3, 18, -1) con.print SI_PrefixFormat(-9.99999999999999999 * 10^-4##, 18, -1), _ "didn't round, stayed µ" con.print con.print "µ, negative, DigitsOut MOD3=2, decimal aligned, thousand separation" con.print SI_PrefixFormat(-1.2345678998765432 * 10^-4, 17, -1) con.print SI_PrefixFormat(-1.2345678998765432 * 10^-5, 17, -1) con.print SI_PrefixFormat(-1.2345678998765432 * 10^-6, 17, -1) con.print SI_PrefixFormat(-9.99999999999999999 * 10^-7##, 17, -1), _ "rounded from n to µ" con.print con.print "n, negative, DigitsOut MOD3=1, decimal aligned, thousand separation" con.print SI_PrefixFormat(-1.2345678998765432 * 10^-7, 16, -1) con.print SI_PrefixFormat(-1.2345678998765432 * 10^-8, 16, -1) con.print SI_PrefixFormat(-1.2345678998765432 * 10^-9, 16, -1) con.print SI_PrefixFormat(-9.99999999999999999 * 10^-10##, 16, -1), _ "rounded from p to n" con.print "------------------------------------------------------------------------------" con.print "p, negative, DigitsOut MOD3=0, not decimal aligned, thousand separation" con.print SI_PrefixFormat(-1.234567890987654 * 10^-10, 15, 0) con.print SI_PrefixFormat(-1.234567890987654 * 10^-11, 15, 0) con.print SI_PrefixFormat(-1.234567890987654 * 10^-12, 15, 0) con.print SI_PrefixFormat(9.9999999999999999 * 10^-13##, 15,0), _ "rounded from f to p" con.print con.print "f, negative, DigitsOut MOD3=2, not decimal aligned, thousand separation" con.print SI_PrefixFormat(-1.23456789098765 * 10^-13, 14, 0) con.print SI_PrefixFormat(-1.23456789098765 * 10^-14, 14, 0) con.print SI_PrefixFormat(-1.23456789098765 * 10^-15, 14, 0) con.print SI_PrefixFormat(-9.9999999999999999 * 10^-16##, 14, 0), _ "rounded from a to f" con.print con.print "a, negative, DigitsOut MOD3=1, not decimal aligned, thousand separation" con.print SI_PrefixFormat(-1.2345678909876 * 10^-16, 13, 0) con.print SI_PrefixFormat(-1.2345678909876 * 10^-17, 13, 0) con.print SI_PrefixFormat(-1.2345678909876 * 10^-18, 13, 0) con.print SI_PrefixFormat(9.9999999999999999 * 10^-19##, 4, 0), _ "rounded from z to a" con.print "------------------------------------------------------------------------------" con.print "z, DigitsOut MOD3=0, not decimal aligned, no thousand separation" con.print SI_PrefixFormat(1.2345 * 10^-19, 12, 0, -1) con.print SI_PrefixFormat(1.2345 * 10^-20, 12, 0, -1) con.print SI_PrefixFormat(1.2345 * 10^-21, 12, 0, -1) con.print SI_PrefixFormat(9.9999999999999999 * 10^-22##, 12, 0, -1), _ "rounded from y to z" con.print con.print "y, DigitsOut MOD3=2, not decimal aligned, no thousand separation" con.print SI_PrefixFormat(1.2345 * 10^-22, 11, 0, -1) con.print SI_PrefixFormat(1.2345 * 10^-23, 11, 0, -1) con.print SI_PrefixFormat(1.2345 * 10^-24, 11, 0, -1) con.print "------------------------- Prefixes added by SI in 2022 -----------------------" con.print "r, DigitsOut MOD=2 , decimal aligned, thousand separation" con.print SI_PrefixFormat(1.2345678976 * 10^-25, 10, -1) con.print SI_PrefixFormat(1.2345678976 * 10^-26, 10, -1) con.print SI_PrefixFormat(1.2345678976 * 10^-27, 10, -1) con.print "q, DigitsOut MOD=1 , decimal aligned, thousand separation" con.print SI_PrefixFormat(1.2345678976 * 10^-28, 10, -1) con.print SI_PrefixFormat(1.2345678976 * 10^-29, 10, -1) con.print SI_PrefixFormat(1.2345678976 * 10^-30, 10, -1) con.print con.print SI_PrefixFormat(7.654321 * 10^-31), "7.654321 * 10^-31 OOR" waitkey$ end function
A GUI demo for folks not having PBCC.
'PBWin10 application to demonstrate SI_PrefixFormat function. 'Release 20221018. Option for no thousands separators added. 'Copyleft 2022 by Dale Yarker; do what you want with this code except claim it, 'or sell it, as yours. No warranty of any kind. 'file demoSIFormatWin.bas (in my project folder) #compile exe #dim all 'cb selected (consecutive CASEs better for AS CONST, else use AS LONG) %ID_FormatBtn = 1001 %ID_ExitBtn = 1002 'not cb selected %ID_DigitsTxtBx = 1100 %ID_DPAlignCkBx = 1101 %ID_DigitsLbl = 1102 %ID_No3DigGrpCkBx = 1103 %ID_NumberLbl = 1104 %ID_NumberTxBx = 1105 %ID_SINumLbl = 1106 %ID_SINumTxtBx = 1107 #include "SI_PrefixFormat.inc" ' callback function MainDlgCB() as long local TempStr, SI_Str as wstring local TempLg, Digits, DPAlign, No3DigGrps as long local NumExt as ext if cb.msg = %wm_command then select case as const cb.ctl case %ID_FormatBtn if cb.ctlmsg = %bn_clicked then 'has non number used characters control get text cb.hndl, %ID_NumberTxBx to TempStr if verify(TempStr, "0123456789.-+Ee"$$) then msgbox "May only contain 0123456789.-+Ee" + $$crlf + _ "Edit, then retry Format.", _ %mb_ok or %mb_iconerror or %mb_taskmodal, _ "Number entry error."$$ control set focus cb.hndl, %ID_NumberTxBx else 'has only number used characters NumExt = val(TempStr) control get text cb.hndl, %ID_DigitsTxtBx to TempStr Digits = val(TempStr) control get check cb.hndl, %ID_DPAlignCkBx to DPAlign control get check cb.hndl, %ID_No3DigGrpCkBx to No3DigGrps SI_Str = SI_PrefixFormat(NumExt, Digits, DPAlign, No3DigGrps) control get text cb.hndl, %ID_SINumTxtBx to TempStr if TempStr = "" then Tempstr = SI_Str else TempStr += $$crlf + SI_Str end if control set text cb.hndl, %ID_SINumTxtBx, TempStr control set focus cb.hndl, %ID_NumberTxBx end if end if case %ID_ExitBtn dialog end cb.hndl end select end if end function function pbmain () as long local hMainDlg, hFixedFont as dword dialog default font "Microsoft Sans Serif", 12, 0, 1 font new "Consolas", 12, 0, 1, 1, 0 to hFixedFont dialog new 0, "SI with prefix formating for PBWin demo.", , , _ 150, 141 to hMainDlg ' control add label, hMainDlg, %ID_DigitsLbl, "Digits in output:"$$, _ 5, 5, 50, 11 control add textbox, hMainDlg, %ID_DigitsTxtBx, "", 56, 5, 15, 11, _ %es_autohscroll or %es_left or %es_number or %ws_border or%ws_tabstop, _ %ws_ex_clientedge or %ws_ex_left control set font hMainDlg, %ID_DigitsTxtBx, hFixedFont control add checkbox, hMainDlg, %ID_DPAlignCkBx, "DP Align:", 105, 5, 40, 11, _ %bs_lefttext or %bs_right or %bs_vcenter or %ws_tabstop, %ws_ex_left control add checkbox, hMainDlg, %ID_No3DigGrpCkBx, _ "Thousands Separation Off:", 50, 21, 95, 11, _ %bs_lefttext or %bs_right or %bs_vcenter or %ws_tabstop, %ws_ex_left control add label, hMainDlg, %ID_NumberLbl, _ "Enter number then press "$$ + $$dq + "Format"$$ + $$dq, 5 , 37, 110, 11 control add textbox, hMainDlg, %ID_NumberTxBx, ""$$, 5, 48, 110, 11 control set font hMainDlg, %ID_NumberTxBx, hFixedFont control add button, hMainDlg, %ID_FormatBtn, "Format"$$, 115, 48, 30, 11 control add label, hMainDlg, %ID_SINumLbl, "SI prefix formated numbers", _ 5, 64, 90, 11 control add textbox, hMainDlg, %ID_SINumTxtBx, "", 5, 75, 140, 45, _ %es_autohscroll or %es_left or %es_multiline or %es_readonly or _ %ws_border or %ws_vscroll, %ws_ex_clientedge or %ws_ex_left control set color hMainDlg, %ID_SINumTxtBx, -1, &h00F8F8F8 control set font hMainDlg, %ID_SINumTxtBx, hFixedFont control add button, hMainDlg, %ID_ExitBtn, "Exit", 115, 125, 30, 11 dialog show modal hMainDlg call MainDlgCB font end hFixedFont end function
Created on 04 September 2022, updated 09 Dec 2022.
To
Domain Home. | To Dale's Notebook index. | To Programs index. |