| ! Fixed Point Number mathematical routines. | |
| ! Version 1.0 (19-Sep-2001) | |
| ! | |
| ! by Matt Albrecht - groboclown@users.sourceforge.net | |
| ! | |
| ! (If you need to edit this file, note that indentations are 4 spaces | |
| ! and tabs are not used.) | |
| ! | |
| ! This has been donated to the Public Domain. Use, abuse, and don't blame me. | |
| ! | |
| ! To prevent dirtying the global namespace, all members of this file begin with | |
| ! "fixedpt_", while members private to this file begin with "fixedpt__". | |
| ! Fixed-point math allows for decimal arithmetic using a fixed number of decimal | |
| ! places. This library uses the standard 16-bit word value to define 8 bits | |
| ! of non-decimal and 8 bits of decimal. | |
| ! Notes about arithmetic with fixed-points: | |
| ! The following operators act exactly the same in normal and fixed modes: | |
| ! + - < > <= >= == | |
| ! The sign operator (negation -) works the same, too. | |
| ! ++ and -- now perform an increment of 1/256 on the values. | |
| ! Modulo is meaningless. | |
| ! | |
| ! The only funky operations you need this for are multiplication and | |
| ! division. | |
| ! Due to signed / unsigned stuff, requires Z-Machine version 5 or older. | |
| System_file; | |
| ! C-like header! | |
| Ifndef FIXEDPT__INCLUDED; | |
| Constant FIXEDPT__INCLUDED; | |
| Message "Adding Fixed-point math library"; | |
| ! Depends upon the longint.h library | |
| Ifndef LONGINT__INCLUDED; | |
| Constant LONGINT__INCLUDED; | |
| Include "longint"; | |
| Endif; | |
| Include "math"; | |
| !------------------------------------------------------------------------------- | |
| ! Locale specific data | |
| Ifndef FIXEDPT_NEGATIVE_SIGN; | |
| Constant FIXEDPT_NEGATIVE_SIGN = "-"; | |
| Endif; | |
| Ifndef FIXEDPT_DECIMAL_POINT; | |
| Constant FIXEDPT_DECIMAL_POINT = "."; | |
| Endif; | |
| Ifndef FIXEDPT_DISPLAYED_DECIMALS; | |
| ! Number of decimal places to display. This cannot be < 1. | |
| Constant FIXEDPT_DISPLAYED_DECIMALS = 4; | |
| Endif; | |
| !------------------------------------------------------------------------------- | |
| ! Used for interior operations | |
| Array fixedpt__long1 -> 4; | |
| Array fixedpt__long2 -> 4; | |
| Array fixedpt__long3 -> 4; | |
| !------------------------------------------------------------------------------- | |
| ! Conversion routines | |
| !------------------------------------------------------------------------------- | |
| !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | |
| ! Displays a fixed-point number as a signed decimal value | |
| ! Use by: | |
| ! print (fixedpt_signed)val; | |
| [ fixedpt_signed | |
| x ! parameter to display | |
| ; ! locals | |
| if (x < 0) | |
| { | |
| print (string)FIXEDPT_NEGATIVE_SIGN; | |
| ! remove the sign from the value | |
| x = -x; | |
| } | |
| fixedpt_unsigned( x ); | |
| ]; | |
| !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | |
| ! Displays a fixed-point number as an unsigned decimal value | |
| ! Use by: | |
| ! print (fixedpt_signed)val; | |
| [ fixedpt_unsigned | |
| x ! parameter to display | |
| modulo count; ! locals | |
| ! display the upper part of the number. | |
| modulo = fixedpt__getUnsignedIntegerPart( x ); | |
| print (math_unsigned)modulo; | |
| ! display the decimal value. | |
| print (string)FIXEDPT_DECIMAL_POINT; | |
| x = fixedpt__getDecimalPart( x ); | |
| ! quick & simple check for easy case. | |
| if (x == 0) | |
| { | |
| print "0"; | |
| return; | |
| } | |
| ! long division | |
| for (count = 0 : count < FIXEDPT_DISPLAYED_DECIMALS : ++count) | |
| { | |
| ! next decimal place | |
| x = x * 10; | |
| ! find the character to display | |
| modulo = x / $100; | |
| !print "[x = ",x,", m = ",modulo,"]"; | |
| if (modulo > 10 || modulo < 0) | |
| { | |
| modulo = 0; | |
| } | |
| print (char)('0' + modulo); | |
| x = x - ($100 * modulo); | |
| if (x == 0) | |
| { | |
| ! don't display any more digits | |
| break; | |
| } | |
| } | |
| ]; | |
| !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | |
| ! Convert the fixed-point number to an integer, ignoring the decimal points. | |
| ! This performs a fixed -> word conversion, as opposed to a fixed -> fixed | |
| ! conversion. | |
| [ fixedpt_unsigned_floor_word | |
| x; ! parameter | |
| return fixedpt__getUnsignedIntegerPart( x ); | |
| ]; | |
| !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | |
| ! Convert the fixed-point number to an integer, ignoring the decimal points. | |
| ! This performs a fixed -> word conversion, as opposed to a fixed -> fixed | |
| ! conversion. | |
| [ fixedpt_signed_floor_word | |
| x; ! parameter | |
| return fixedpt__getSignedIntegerPart( x ); | |
| ]; | |
| !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | |
| ! Convert the fixed-point number to an integer, rounding up to the next integer | |
| ! if the decimal part is > 0. | |
| ! This performs a fixed -> word conversion, as opposed to a fixed -> fixed | |
| ! conversion. | |
| [ fixedpt_unsigned_ceiling_word | |
| x ! parameter | |
| i; ! local | |
| i = fixedpt__getUnsignedIntegerPart( x ); | |
| if (fixedpt__getDecimalPart( x ) > 0) ++i; | |
| return i; | |
| ]; | |
| !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | |
| ! Convert the fixed-point number to an integer, rounding up to the next integer | |
| ! if the decimal part is > 0. | |
| ! This performs a fixed -> word conversion, as opposed to a fixed -> fixed | |
| ! conversion. | |
| [ fixedpt_signed_ceiling_word | |
| x ! parameter | |
| i; ! local | |
| i = fixedpt__getSignedIntegerPart( x ); | |
| if (fixedpt__getDecimalPart( x ) > 0) ++i; | |
| return i; | |
| ]; | |
| !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | |
| ! Convert the fixed-point number to an integer, rounding to the nearest integer. | |
| ! This performs a fixed -> word conversion, as opposed to a fixed -> fixed | |
| ! conversion. | |
| [ fixedpt_unsigned_round_word | |
| x ! parameter | |
| i; ! local | |
| i = fixedpt__getUnsignedIntegerPart( x ); | |
| if (fixedpt__getDecimalPart( x ) >= $80) ++i; | |
| return i; | |
| ]; | |
| !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | |
| ! Convert the fixed-point number to an integer, rounding to the nearest integer. | |
| ! This performs a fixed -> word conversion, as opposed to a fixed -> fixed | |
| ! conversion. | |
| [ fixedpt_signed_round_word | |
| x ! parameter | |
| i; ! local | |
| i = fixedpt__getSignedIntegerPart( x ); | |
| if (fixedpt__getDecimalPart( x ) >= $80) ++i; | |
| return i; | |
| ]; | |
| !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | |
| ! Convert a word integer into an unsigned fixed number. | |
| ! If the word value is >= 256, it is truncated to 255. | |
| [ fixedpt_word_to_unsigned_fixed | |
| x; ! parameter | |
| if (x > $ff) x = $ff; | |
| return math_unsigned_shift( x, 8 ); | |
| ]; | |
| !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | |
| ! Convert a word integer into a signed fixed number. | |
| ! If the word value is >= 128, it is truncated to 127, and if it is | |
| ! < -128, it is truncated to -128. | |
| [ fixedpt_word_to_signed_fixed | |
| x; ! parameter | |
| if (x >= $80) | |
| { | |
| ! return biggest signed fixed | |
| return $7fff; | |
| } | |
| else | |
| if (x <= -128) | |
| { | |
| ! return smallest signed fixed | |
| return $8000; | |
| } | |
| if (x < 0) | |
| { | |
| return math_signed_shift( x, 8 ) - $ff; | |
| } | |
| return math_signed_shift( x, 8 ); | |
| ]; | |
| !------------------------------------------------------------------------------- | |
| ! Arithmetic | |
| !------------------------------------------------------------------------------- | |
| !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | |
| ! Multiply two signed values together | |
| ! - due to possible overflow, this uses the longint routines to perform the | |
| ! operation. | |
| [ fixedpt_signed_mul | |
| x y ! parameters | |
| r s; ! locals | |
| ! operation = (x * y) >> 8; | |
| ! long1 = x | |
| math__set_signed_word_to_long( x, fixedpt__long1 ); | |
| ! long2 = y | |
| math__set_signed_word_to_long( y, fixedpt__long2 ); | |
| ! long3 = long1 * long2 | |
| LongMul( fixedpt__long3, fixedpt__long1, fixedpt__long2 ); | |
| ! Due to decimal place movement, the resulting value is in the top 3 bytes | |
| ! of long3. | |
| if (fixedpt__long3->0 < 0 && fixedpt__long3 ~= $ff) | |
| { | |
| ! overflow - return smallest signed fixed | |
| return $8000; | |
| } | |
| else | |
| if (fixedpt__long3->0 > 0) | |
| { | |
| ! overflow - return biggest signed fixed | |
| return $7fff; | |
| } | |
| ! no overflow | |
| r = fixedpt__long3->1 & $ff; | |
| s = fixedpt__long3->2 & $ff; | |
| return math_signed_shift( r, 8 ) + s; | |
| ]; | |
| !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | |
| ! Multiply two unsigned values together | |
| ! - due to possible overflow, this uses the longint routines to perform the | |
| ! operation. | |
| [ fixedpt_unsigned_mul | |
| x y ! parameters | |
| r s; ! locals | |
| ! operation = (x * y) >> 8; | |
| ! long1 = x | |
| math__set_unsigned_word_to_long( x, fixedpt__long1 ); | |
| ! long2 = y | |
| math__set_unsigned_word_to_long( y, fixedpt__long2 ); | |
| ! long3 = long1 * long2 | |
| LongMul( fixedpt__long3, fixedpt__long1, fixedpt__long2 ); | |
| if (fixedpt__long3->0 ~= 0) | |
| { | |
| ! overflow - return biggest unsigned fixed | |
| return $ffff; | |
| } | |
| ! no overflow | |
| r = fixedpt__long3->1 & $ff; | |
| s = fixedpt__long3->2 & $ff; | |
| return math_unsigned_shift( r, 8 ) + s; | |
| ]; | |
| !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | |
| ! Divide two signed values together (returns x / y) | |
| ! - due to possible overflow, this uses the longint routines to perform the | |
| ! operation. | |
| [ fixedpt_signed_div | |
| x y ! parameters | |
| r s; ! locals | |
| ! operation = (x / y) << 8; | |
| ! we don't want to loose precision, so perform the shifting first. | |
| ! long1 = x << 8 | |
| LongSet( fixedpt__long1, 0, | |
| math_unsigned_shift( x, 8 ) & $ff, (x & $ff), 0 ); | |
| if (x < 0) | |
| { | |
| fixedpt__long1->0 = $ff; | |
| } | |
| ! long2 = y | |
| math__set_signed_word_to_long( y, fixedpt__long2 ); | |
| ! long3 = long1 / long2 | |
| LongSignDiv( fixedpt__long3, fixedpt__long1, fixedpt__long2 ); | |
| r = fixedpt__long3->2 & $ff; | |
| s = fixedpt__long3->3 & $ff; | |
| return math_signed_shift( r, 8 ) + s; | |
| ]; | |
| !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | |
| ! Divide two unsigned values together (returns x / y) | |
| ! - due to possible overflow, this uses the longint routines to perform the | |
| ! operation. | |
| [ fixedpt_unsigned_div | |
| x y ! parameters | |
| r s; ! locals | |
| ! operation = (x / y) << 8; | |
| ! we don't want to loose precision, so perform the shifting first. | |
| ! long1 = x << 8 | |
| LongSet( fixedpt__long1, 0, | |
| math_unsigned_shift( x, -8 ) & $ff, (x & $ff), 0 ); | |
| ! long2 = y | |
| math__set_unsigned_word_to_long( y, fixedpt__long2 ); | |
| ! long3 = long1 / long2, long1 = modulo | |
| LongUnsignDivMod( fixedpt__long3, fixedpt__long1, | |
| fixedpt__long1, fixedpt__long2 ); | |
| r = fixedpt__long3->2 & $ff; | |
| s = fixedpt__long3->3 & $ff; | |
| return math_unsigned_shift( r, 8 ) + s; | |
| ]; | |
| !------------------------------------------------------------------------------- | |
| ! Private members | |
| !------------------------------------------------------------------------------- | |
| !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | |
| ! Returns the upper 8 bits of the given word. | |
| [ fixedpt__getUnsignedIntegerPart | |
| x; ! parameters | |
| return math_unsigned_shift( x, -8 ) & $ff; | |
| ]; | |
| !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | |
| ! Returns the upper 8 bits of the given word. | |
| [ fixedpt__getSignedIntegerPart | |
| x; ! parameters | |
| ! no masking to keep the sign bits | |
| return math_signed_shift( x, -8 ); | |
| ]; | |
| !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | |
| ! Returns the lower 8 bits of the given word. | |
| [ fixedpt__getDecimalPart | |
| x; ! parameters | |
| return x & $ff; | |
| ]; | |
Xet Storage Details
- Size:
- 11.9 kB
- Xet hash:
- d792ec6786456b6a8d4d4d57833ea8b5a74f39c320c1f431897241242470a44e
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.