home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Columbia Kermit
/
kermit.zip
/
pub
/
scripts
/
ckermit
/
twoscomplement
< prev
next >
Wrap
Lisp/Scheme
|
2020-01-01
|
5KB
|
125 lines
# Macros to display signed decimal numbers in two's complement hexadecimal
# notation. Because the code underlying most of Kermit's arithmetic and
# numeric comparison functions uses machine arithmetic, it is necessary to
# employ string operations and lexical comparisons to handle edge cases.
# Works in both C-Kermit (8.0 and later) and K95 (2.0 and later).
#
# F. da Cruz, Columbia University, 19 November 2007
# Macro BINTOHEX converts a binary string to hex.
# \%1 = binary number (string)
# \%2 = word size in bits
#
# \fradix() is constrained by machine integer word length
# so we do it in pieces in case the number is too big.
#
define BINTOHEX {
undef \%6 # Result accumulator
for \%9 1 \%2 4 { # Do four bits at at a time
.\%8 := \fsubstr(\%1,\%9,4) # Get chunk of 4
if not def \%8 break # Make sure we have one
.\%7 := \fradix(\%8,2,16) # Convert to Hex digit
.\%6 := \%6\%7 # Accumulate
}
return \%6
}
# Macro DECTOHEX converts a signed decimal number to 2's complement hex.
# \%1 = decimal number string (default 0)
# \%2 = word size in bits (must be a power of two, 4 or greater, default 32)
#
# Because of how \fradix() works, this function operates correctly only
# for numbers whose absolute value fits in the machine's integer word.
#
define DECTOHEX {
local m1
if not def \%1 .\%1 = 0 # Supply default if no arg given
if not numeric \%1 return NOT_A_NUMBER:\%1 # Check that arg is a number
if not def \%2 .\%2 := 32 # Use 32 bits if no second arg
(setq m1 (truncate (- (^ 2 (- \%2 1)) 1))) # Largest positive number
if eq "\fsubstr(\%1,1,1)" "+" .\%1 := \fsubstr(\%1,2) # strip any + sign
if not eq "\fsubstr(\%1,1,1)" "-" { # Argument is signed?
.\%1 := \flpad(\%1,\flen(\v(svalue)),0) # No - check magnitude
if lgt \%1 \v(svalue) return OVERFLOW
return \flpad(\fradix(\%1,10,16),(\%2 / 4),0) # Convert to hex and pad
}
.\%1 := \fsubstr(\%1,2) # Negative number - remove sign
.\%1 := \flpad(\%1,\flen(\m(m1)),0) # Must use lexical comparison
(++ m1) # Avoid fencepost error
if llt \m(m1) \%1 return UNDERFLOW # Check magnitude
.\%9 := \flpad(\fradix(\%1,10,2),\%2,0) # Convert to binary and pad
.\%8 ::= \frindex(1,\%9) - 1 # Find first 1 on the right
if == \%8 -1 { # Watch out for negative 0
return \frepeat(0,\%2 / 4)
}
.\%7 := \fsubstr(\%9,1,\%8) # Split string here
.\%6 := \fsubstitute(\%7,01,10) # Complement bits in left part
.\%5 := \%6\fsubstr(\%9,\%8+1) # Put back with right part
.\%4 := \fexec(bintohex \%5 \%2) # Convert to hex
return \%4
}
# Test the functions...
set take echo on
echo \fexec(dectohex 7) # No word size specified
echo \fexec(dectohex)
echo \fexec(dectohex 7 4) # 4-bit word
echo \fexec(dectohex 8 4)
echo \fexec(dectohex -8 4)
echo \fexec(dectohex -9 4)
echo \fexec(dectohex 99 4)
echo \fexec(dectohex 0 8) # 8-bit word
echo \fexec(dectohex -0 8)
echo \fexec(dectohex 1 8)
echo \fexec(dectohex +1 8)
echo \fexec(dectohex 2 8)
echo \fexec(dectohex 3 8)
echo \fexec(dectohex 4 8)
echo \fexec(dectohex 5 8)
echo \fexec(dectohex 6 8)
echo \fexec(dectohex 7 8)
echo \fexec(dectohex -1 8)
echo \fexec(dectohex -2 8)
echo \fexec(dectohex -3 8)
echo \fexec(dectohex -4 8)
echo \fexec(dectohex -5 8)
echo \fexec(dectohex -6 8)
echo \fexec(dectohex -7 8)
echo \fexec(dectohex -8 8)
echo \fexec(dectohex 64 8)
echo \fexec(dectohex 65 8)
echo \fexec(dectohex -128 8)
echo \fexec(dectohex 0 16) # 16-bit word
echo \fexec(dectohex 64 16)
echo \fexec(dectohex 65 16)
echo \fexec(dectohex -128 16)
echo \fexec(dectohex -32768 16)
echo \fexec(dectohex 99999 16)
echo \fexec(dectohex -99999 16)
echo \fexec(dectohex 0 32) # 32-bit word
echo \fexec(dectohex 1 32)
echo \fexec(dectohex 16383 32)
echo \fexec(dectohex 2147483647 32)
echo \fexec(dectohex -1 32)
echo \fexec(dectohex -2 32)
echo \fexec(dectohex -2147483647 32)
echo \fexec(dectohex -2147483648 32)
echo \fexec(dectohex 0 64) # 64-bit word
echo \fexec(dectohex 2147483647 64)
echo \fexec(dectohex -1 64)
echo \fexec(dectohex -2 64)
echo \fexec(dectohex -2147483647 64)
echo \fexec(dectohex -2147483648 64)
echo \fexec(dectohex 0 128) # 128-bit word
echo \fexec(dectohex 1 128)
echo \fexec(dectohex -1 128)
echo \fexec(dectohex -2 128)
set take echo off
if c-kermit exit