The HotDocs Computation Archive  

Problem. HotDocs' "9 1/8" fraction formatting is limited to eighths (and multiples thereof). Thus it forces all decimal values into one of the following fractions: 1/8, 1/4, 3/8, 1/2, 5/8, 3/4, 7/8. There is not a format that accomodates anything but eighths. Further, HotDocs will include "0/8" if your number is whole.
Solution. These computations will format any decimal value as its representative fraction. So .1 becomes 1/10, .67 becomes 2/3, and .09 becomes 9/100. Your number is then returned as a text string formatted as "1 2/3". If there is no decimal value, the fraction will be omitted.
Both computations will work asis. They look daunting, but the work has been done for you. As long as you create the required elements, you can simply copy and paste the computations.
The computations require the looping mechanism described in Computation #0015: Loops via REPEAT. Please refer to that page for some caveats about this method.
Differences. The first computation is the original "Smarter Fraction Formatter." It will work up to two decimal places. Its highest precision is 1/100. It is included here as a fairly accessible model of how this type of computation is performed.
The second computation, the "(Even) Smarter Fraction Formatter," uses a much more sophisticated algorithm to produce the highest precision available in HotDocs: 1/1000000000 (one onebillionth). Note that it is no harder to use than the first. Just copy and paste.
See also, Computation #0051: Format a Number as "nine point seven five", #0052: Format a Fraction as "four and one half", #0062: "All (100%)", #0150: Decimal Formatter.
• • • • • • •
Original Computation:
""
// Round to two decimal places
SET Tempt TO "«ROUND( NumVar, 2 ):9.00»"
// Numerator is the decimal value
SET Numerator TO INTEGER( LAST( Tempt, 2 ) )
// No decimal part. Just return their number.
IF Numerator = 0
"«NumVar:9»"
// There is a decimal. Find the fraction.
ELSE
// Special handling: 1/3
IF Numerator = 33
SET Numerator TO 1
SET Denominator TO 3
// Special handling: 2/3
ELSE IF Numerator = 66 OR Numerator = 67
SET Numerator TO 2
SET Denominator TO 3
// Find the fraction
ELSE
// Denominator is 100
SET Denominator TO 100
// Set up a loop
SET LoopLimit[ 100 ] TO "x"
ASK NONE
REPEAT Loop
// Count backward from 100, looking for greatest common multiples
SET Tempn TO 101  COUNTER
// Is this a common multiple?
IF REMAINDER( Numerator , Tempn ) = 0
AND REMAINDER( Denominator , Tempn ) = 0
// Yes! Divide both by the multiple
SET Numerator TO Numerator / Tempn
SET Denominator TO Denominator / Tempn
END IF
END REPEAT
// Clean up the loop
REPEAT Loop
SET LoopLimit TO UNANSWERED
END REPEAT
ASK DEFAULT
END IF
// Format the fraction
"«NumVar:9» «Numerator»/«Denominator»"
END IF
Required Elements:
The NittyGritty. The computation first rounds your number to two decimal places and puts this value into a temporary text variable, Tempt. This is necessary to extract the decimal portion. We can grab the decimal portion by just taking the LAST two characters of Tempt and converting them to an integer. This will now be our numerator (e.g. .25 = 25/100).
At this point there is no need to continue if there is no numerator, so if that is the case the computation will simply return the integer portion of NumVar. But if there is a numerator, we should examine it to see if we have either 1/3 or 2/3, since these cannot be produced by our loop (they would end up as 33/100 and 33/50, respectively). If the numerator is 33, we can just change it to 1 and make the denominator 3 and be done. Or if the numerator is 66 or 67 (in the event of rounding), we make the numerator 2 and the denominator 3.
Failing the previous tests, we now are forced to come up with the fraction on our own. The starting value of the fraction is n/100. This will almost always need to be reduced (e.g. 50/100 can be reduced to 1/2). We do this by counting down backwards from 100, trying to find the greatest common multiples for the numerator and the denominator. Each time we find a common multiple (i.e. there is no remainder when they are divided by the number) we perform the division to reduce the numbers. By the time our count has reached 1, we have effectively reduced our original fraction.
Finally, we return the formatted number in the form 1 2/3. You can tweak the formatting to your liking.
Contributor: LegalCS
• • • • • • •
HighPrecision Computation:
""
SET Numeratorn TO NumVar  TRUNCATE(NumVar, 0 )
SET WholeNumbern TO TRUNCATE(NumVar, 0 )
// No decimal part. Just return the number.
IF Numeratorn = 0
"«NumVar:9»"
// There is a decimal. Find the fraction.
ELSE
// Initialize vars
SET Testn TO Numeratorn
SET FractionSetb TO FALSE
// Check to see if value > 1/2 (algorithm only works below 1/2)
// If value > 1/2, find result for (1  value)
IF Testn > 0.5
SET GreaterThanHalfb TO TRUE
SET Testn TO 1  Testn
ELSE
SET GreaterThanHalfb TO FALSE
END IF
// Set up a loop
SET LoopLimit[ 10 ] TO "x"
SET Tempn TO Testn
ASK NONE
REPEAT Loop
// Run 10 iterations, looking for least
// common denominator
IF FractionSetb = FALSE
SET Denominatorn TO ROUND((1 / Tempn), 8)
// Is this a common denominator?
// If NumVar has 10 digit precision (i.e., database variable
// or combined HotDocs vars entered by user), use this test
IF ABSOLUTE VALUE(Denominatorn  ROUND(Denominatorn, 0)) / (MIN(Denominatorn, 100)) < 0.00125
// If NumVar is limited to 5 digit precision (i.e., standard
// single HotDocs var entered by user), use this test
// IF ABSOLUTE VALUE(Denominatorn  ROUND(Denominatorn, 0)) / (MIN(Denominatorn, 50)) < 0.0075
// Success! Set condition as true
SET FractionSetb TO TRUE
SET LoopAnsweredn TO 1
SET LoopFractionn TO 1
ELSE
// Failure, prepare for next iteration
SET Tempn TO Denominatorn  TRUNCATE(Denominatorn, 0)
IF Tempn > 0.5
SET Tempn TO 1  Tempn
END IF
SET LoopFractionn TO Tempn
SET LoopAnsweredn TO 1
END IF
ELSE
SET LoopResultn TO 1
END IF
END REPEAT
// Now do the loop in reverse
REPEAT Loop
SET Countern TO 11  COUNTER
SET Answeredn TO LoopAnsweredn[ Countern ]
IF ANSWERED( Answeredn )
// Pull result from previous iteration
SET Countern TO Countern + 1
IF Countern = 11
SET Tempn TO 1
ELSE
SET Tempn TO LoopResultn[ Countern ]
END IF
SET Countern TO Countern  1
// Divide by the fraction in this iteration
SET Tempn TO ROUND( Tempn / LoopFractionn[ Countern ], 0 )
// Set result for this iteration
SET LoopResultn[ Countern ] TO Tempn
END IF
END REPEAT
// Set numerator and denominator
SET Numerator TO ROUND(LoopResultn[ 1 ], 0)
SET Denominator TO ROUND(Numerator / Testn, 0)
// Clean up the loop
REPEAT Loop
SET LoopLimit TO UNANSWERED
SET LoopFractionn TO UNANSWERED
SET LoopAnsweredn TO UNANSWERED
SET LoopResultn TO UNANSWERED
END REPEAT
ASK DEFAULT
IF FractionSetb = FALSE
//Did not work, set to "nnn/1000"
SET Testn TO Testn * 1000
SET Numerator TO ROUND(Testn, 0)
SET Denominator TO 1000
// See if numerator and denominator are both
// divisible by prime factors of 1000, 2*2*2*5*5*5
IF REMAINDER(Numerator, 2) = 0
AND REMAINDER(Denominator, 2) = 0
SET Numerator TO Numerator / 2
SET Denominator TO Denominator / 2
END IF
IF REMAINDER(Numerator, 2) = 0
AND REMAINDER(Denominator, 2) = 0
SET Numerator TO Numerator / 2
SET Denominator TO Denominator / 2
END IF
IF REMAINDER(Numerator, 2) = 0
AND REMAINDER(Denominator, 2) = 0
SET Numerator TO Numerator / 2
SET Denominator TO Denominator / 2
END IF
IF REMAINDER(Numerator, 5) = 0
AND REMAINDER(Denominator, 5) = 0
SET Numerator TO Numerator / 5
SET Denominator TO Denominator / 5
END IF
IF REMAINDER(Numerator, 5) = 0
AND REMAINDER(Denominator, 5) = 0
SET Numerator TO Numerator / 5
SET Denominator TO Denominator / 5
END IF
IF REMAINDER(Numerator, 5) = 0
AND REMAINDER(Denominator, 5) = 0
SET Numerator TO Numerator / 5
SET Denominator TO Denominator / 5
END IF
END IF
//If value was > .5, invert numerator result
IF GreaterThanHalfb
SET Numerator TO Denominator  Numerator
END IF
// Format the fraction
"«WholeNumbern» «Numerator:9999»/«Denominator:9999»"
END IF
Required Elements: (Note: All variables but NumVar are temporary variables. Set their Advanced options to "Ask only in dialog," "Don't warn if unanswered," and "Don't save in answer file")
This "(Even) Smarter Fraction" computation will convert a decimal to a fraction for any numerator and denominator, denominator up to the limit of the precision of the HotDocs variable being tested. If the tested variable has ten digit precision (the HotDocs maximum precision), both the numerator and denominator can (theoretically) be between 1 and 10,000,000,000. However, even with 10 digit precision, results get unpredictable below 1/100000 and above 99999/100000.
If the computation is unable to come up with a decimal using its algorithm, it will convert the decimal to "nnn/1000", and then reduce by any applicable prime factors of both nnn and 1000.
Thanks to the Computation Archive for the original "Smarter Fraction" computation and for the structure used in this computation.
A Note on 1/3 and 2/3. This computation automatically recognizes 1/3 and 2/3, but only at three decimal places. Note the fractions produced by each of the following values:
.300 > 3/10 .330 > 33/100 .333 > 1/3 .600 > 3/5 .660 > 33/50 .666 > 2/3
If your variable is limited to two decimal places, you will need to do a special check for .33 and .66. The technique is demonstrated in the original "Smarter Fraction" computation above.
Contributor: Benjamin Reich, Esquire