home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / ckscripts / cmp < prev    next >
Text File  |  2020-01-01  |  3KB  |  66 lines

  1. # Macro CMP - Compares numbers even if they are bigger than machine word size.
  2. #  \%1 = arithmetic comparison operator (>, <, =, etc, listed below);
  3. #  \%2 = first number (signed or unsigned decimal, integer or floating-point);
  4. #  \%3 = second number (ditto).
  5. #
  6. # Succeeds if comparison is true, fails if not, or if called incorrectly.
  7. # Example:
  8. #
  9. #  cmp > 987 -0.10001824
  10. #  if success { commands if true } else { commands if false }
  11. #
  12. # For comparison the numbers are normalized to 24 decimal places with
  13. # leading zeros before the decimal point, and 24 decimal places with trailing
  14. # zeros after the decimal point and then compared lexically, hence no 
  15. # limitation is imposed by machine word size.  You can change the precision
  16. # by defining \%9 to any other number you wish.
  17. #
  18. # Illustrates:
  19. #  . Use of \%9, \%8, ... (unused macro args) as local temporary variables.
  20. #  . Using \findex() to see if operator matches any of the legal ones.
  21. #  . Compact substring notation e.g. \:(\%2[1:1])
  22. #  . Using \fverify() to see if a number is all 0's
  23. #  . Using \fword() to break floating-point number into whole & fraction parts
  24. #  . Using \flpad() and \frpad() to format number so that lexical comparison
  25. #    gives the result that arithmetic comparison would have given.
  26. #
  27. # F. da Cruz, Columbia U, 18-19 December 2007
  28. #
  29. def cmp {
  30.     .\%9 = 24  # Digits before & after decimal point for normalization
  31.     .\%8 = 0   # sign of \%2: 0(+) 1(-)
  32.     .\%7 = 0   # sign of \%3: 0(+) 1(-)
  33.     # Verify arguments
  34.     if < \v(argc) 4 end 2 "Usage: CMP operator number number"
  35.     if not float \%2 end 2 "CMP: operand not numeric '\%2'"
  36.     if not float \%3 end 2 "CMP: operand not numeric '\%3'"
  37.     if not \findex(:\%1:,:<:>:<=:>=:!=:=:==:) end 2 "CMP: Bad operator '\%1'"
  38.     # Check sign of each number
  39.     if eq "\:(\%2[1:1])" "+" .\%2 := \:(\%2[2]) # Strip any leading plus sign
  40.     if eq "\:(\%3[1:1])" "+" .\%3 := \:(\%3[2])
  41.     if eq "\:(\%2[1:1])" "-" { .\%7 = 1, .\%2 := \:(\%2[2]) } # Note minuses
  42.     if eq "\:(\%3[1:1])" "-" { .\%8 = 1, .\%3 := \:(\%3[2]) } # and strip them
  43.     if not \fverify(0,\%2) .\%7 = 0 # watch out for "-0"
  44.     if not \fverify(0,\%3) .\%8 = 0 # watch out for "-0"
  45.     # Handle easy cases first
  46.     switch \%7\%8 {
  47.       :01, if \findex(:\%1:,:>:>=:!=:) end 0, end 1 # Signs differ
  48.       :10, if \findex(:\%1:,:<:<=:!=:) end 0, end 1 # Signs differ
  49.       :11, .\%5 := \%2, .\%2 := \%3, .\%3 = \%5 # Both negative - swap args
  50.     }
  51.     # Get here if we must compare the magnitudes (signs 00 or 11)
  52.     # Normalize for lexical comparison \%9 digits before & after decimal point
  53.     .\%2 := \flpad(\fword(\%2,1),\%9,0).\frpad(\fword(\%2,2),\%9,0)
  54.     .\%3 := \flpad(\fword(\%3,1),\%9,0).\frpad(\fword(\%3,2),\%9,0)
  55.     # Make the desired comparison
  56.     switch \%1 {
  57.       :<,   if LLT \%2 \%3 end 0, end 1
  58.       :>,   if LGT \%2 \%3 end 0, end 1
  59.       :\=,  if EQU \%2 \%3 end 0, end 1
  60.       :\==, if EQU \%2 \%3 end 0, end 1
  61.       :!=,  if NOT EQU \%2 \%3 end 0, end 1
  62.       :<=,  if NOT LGT \%2 \%3 end 0, end 1
  63.       :>=,  if NOT LLT \%2 \%3 end 0, end 1
  64.     }
  65. }
  66.