disast.rs :: journal

Fixed-Width Arithmetic

Fixed-width arithmetic is a form of integer arithmetic where rational numbers are scaled to a whole-number value, with an implied "decimal point".

Percentages are an example of this, e.g. 5 percent is a whole-number representation of 0.05. In this case, the scale is 100

Additional precision is possible by scaling to higher numbers -- scaling to 10000 gives 4 decimal points of precision.

One may also scale to non-decimal values, for example, 214. Rather than decimal points of precision, gives 14 bits of fractional precision. For an unsigned 32 bit integer, this means any value from [0 - 16383] represents a scaled number between 0 and 1, with a "1" value of 16384. The largest unscaled value that may be represented is 232-18 = 218 = 262144.

 
 bit-wise layout of a 32-bit unsigned integer, scaled to 14 bits of precision. 
 whole-number bits...... . fractional bits. 
 0000 0000 0000 0000 001 . 0 0000 0000 0000 
 

Examples

The following is a Modal program that calculates the average interest rate of 3 loans, to 4 decimal points of precision.

This example defines the scale (*/) operator, which takes three arguments on a stack: numerator, denominator, and scalar. The operator first multiplies the numerator by the scalar, then applies the denominator -- resulting in a scaled fixed-width number.

(this example also illustrates how to simulate forth in modal)

 
 <> (:: ?x) () :: comment 
 <> ($> lit ?x) (?x $>) :: literal 
 <> (?y ?x $> concat) (?(?^ ?^) (?y ?x) $> ) 
 <> ($> .) (#print $>) 
 <> (?: #print) (?:) 
 
 :: (stack operators) 
 <> (?x ?y $> swap) (?y ?x $>) 
 <> (?x $> dup) (?x ?x $>) 
 <> (?a ?b ?c $> swapd) (?b ?a ?c $>) 
 <> (?a ?b ?c $> rotate) (?c ?b ?a $>) 
 <> (?a ?b ?c $> rollup) (?c ?a ?b $>) 
 <> (?a ?b ?c $> rolldown) (?b ?c ?a $>) 
 
 :: (math coprocessor) 
 <> (?1 ?0 $> `?:) (?: $>) :: (arithmetic on 2 terms) 
 <> (?2 ?1 ?0 $> ``?:) (?: $>) :: (arithmetic on 3 terms) 
 
 :: (Step 1: Multiply each loan balance by the corresponding interest rate ) 
 :: (Step 2: Add the products together) 
 :: (Step 3: Divide the sum by the total debt) 
 
 <> (*/) (rollup `* `/) :: (scale operator: n1 n2 n3 -- n) 
 <> (^1) (lit 16834) :: (fixed-width scalar, 2^14) 
 <> (*.) (^1 */) :: (scaled multiply) 
 <> (/.) (^1 swap */) :: (scaled division) 
 :: (get the average interest rate of 3 loans: 
 $8710 at .0365 (3.65%) 
 $3948 at .0438 (4.38%) 
 $9810 at .0517 (5.17%)) 
 $> 
 lit 365 lit 10000 /. lit 8710 `* 
 lit 438 lit 10000 /. lit 3948 `* 
 lit 517 lit 10000 /. lit 9810 `* ``+ 
 lit 8710 lit 3948 lit 9810 ``+ swap `/ lit 10000 *. 
 lit .0 swap concat . 
 
 Completed in 89 rewrites. 
 .0443