# Macros to convert signed decimal numbers to two's complement hexadecimal # notation. This version does not use machine arithmetic; it does everything # with strings, so is able to handle integers of any size. As written it # accommodates word sizes of 4, 8, 16, 32, 64, and 128 bits. Other word # sizes can be added by changing the definitions at the top. # # Because machine arithmetic is not used, this version is considerably slower # than the first one but it works for numbers that don't fit in 32 bits in # Kermit 95 and in 32-bit versions of C-Kermit. # # F. da Cruz, Columbia University, 28 December 2007 .legal = :4:8:16:32:64:128: # Legal word sizes # Largest positive integer for the supported word sizes .maxint<4> = 7 .maxint<8> = 127 .maxint<16> = 32767 .maxint<32> = 2147483647 .maxint<64> = 9223372036854775807 .maxint<128> = 340282366920938463463374607431768211455 # Ditto plus one (because we can't necessarily do arithmetic on big numbers) .maxplusone<4> = 8 .maxplusone<8> = 128 .maxplusone<16> = 32768 .maxplusone<32> = 2147483648 .maxplusone<64> = 9223372036854775808 .maxplusone<128> = 340282366920938463463374607431768211456 # 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 .\%1 := \flpad(\%1,\%2,0) # Pad to size if necessary 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 } def DIV2 { # Divide decimal string by two local \%i undef \%6 \%7 result for \%i 1 \flen(\%1) 1 { # One digit at a time. .\%9 := \%7\:(\%1[\%i:1]) # Get a digit. .\%8 ::= \%9/2 # Divide it by 2 .\%7 ::= \%9%2 # Get remainder .\%6 := \%6\%8 # Accumulate result } .result := \%6 # Make result .remainder := \%7 # and remainder visible } def DTOB { # Convert decimal string to binary while true { # without using machine div2 \%1 # arithmetic. .\%6 := \m(remainder)\%6 .\%1 := \m(result) if not \fverify(0,\%1) break } return \%6 } # Macro DECTOHEX converts a signed decimal number to 2's complement hex, # using the macros defined above as workers. # \%1 = decimal number string (default 0) # \%2 = word size in bits # (must be a power of two, 4 or greater, default 32, max 128) # Returns result in \v(result) and/or as value of \fexec(dectohex arg arg). # define DECTOHEX { local digits 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 if not \findex(:\%2:,\m(legal)) end 1 "UNSUPPORTED WORD SIZE - \%2" .digits := \flen(\m(maxint<\%2>)) # Number of digits in it if eq "\fsubstr(\%1,1,1)" "+" .\%1 := \fsubstr(\%1,2) # strip any + sign if not eq "\fsubstr(\%1,1,1)" "-" { # If argument is not signed... if lgt \flpad(\%1,\m(digits),0) \m(maxint<\%2>) return OVERFLOW dtob \%1 # Convert from decimal to binary bintohex \v(return) \%2 # And from binary to hex return \flpad(\v(return),(\%2/4),0) # Return padded result } .\%1 := \fsubstr(\%1,2) # Negative number - remove sign .\%1 := \flpad(\%1,\flen(\m(maxint<\%2>)),0) # Must use lexical comparison if llt \m(maxplusone<\%2>) \%1 return UNDERFLOW # Check magnitude dtob \%1 # Convert to binary .\%9 := \flpad(\v(return),\%2,0) # and pad .\%8 ::= \frindex(1,\%9) - 1 # Find first 1 on the right if == \%8 -1 return \frepeat(0,\%2 / 4) # Watch out for negative 0 .\%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... def try { # Note \v(time) lacks the fractional part in Windows for some reason. .t1 := \v(ftime) # Current time .result := \fexec(dectohex \%1 \%2) # Do the conversion .t2 := \v(ftime) # New time (setq t3 (- t2 t1)) # Difference echo \%1[\%2] = \m(result) [\ffpround(\m(t3),2) sec] # Print } try 7 # No word size specified try 7 4 # 4-bit word try 8 4 try -8 4 try -9 4 try 99 4 try 0 8 # 8-bit word try -0 8 try 1 8 try +1 8 try 2 8 try 3 8 try 4 8 try 5 8 try 6 8 try 7 8 try -1 8 try -2 8 try -3 8 try -4 8 try -5 8 try -6 8 try -7 8 try -8 8 try 64 8 try 65 8 try -128 8 try 0 16 # 16-bit word try 64 16 try 65 16 try -128 16 try -32768 16 try 99999 16 try -99999 16 try 0 32 # 32-bit word try 1 32 try 16383 32 try 2147483647 32 try -1 32 try -2 32 try -2147483647 32 try -2147483648 32 try 0 64 # 64-bit word try 2147483647 64 try -1 64 try -2 64 try 1234567890 64 try -2147483647 64 try -2147483648 64 try 8224373093854475231 64 try 0 128 # 128-bit word try 1 128 try -1 128 try -2 128 try 317282366902934863643347307341786875499 128 if c-kermit exit