Significant Digits Version:
Rounds at the chosen significant digit.
Code: Select all
<run_actions ref="RoundSig" result="$rounded">
<param name="number" value="1234.567" />
<param name="d" value="3" />
</run_actions>
Code: Select all
<run_actions ref="RoundSig" result="$rounded">
<param name="number" value="0.01987" />
<param name="d" value="2" />
<param name="direction" value="'down'" />
</run_actions>
Code: Select all
<library name="RoundSig" purpose="run_actions">
<params>
<param name="number" />
<param name="d" />
<param name="direction" default="null" /> <!-- optional: 'up' or 'down' -->
</params>
<actions>
<!-- Absolute value -->
<set_value name="$absN" exact="[$number, -$number].max" />
<set_value name="$mag" exact="0" />
<!-- Count how many times we divide by 10 before it's < 1 -->
<do_while value="$absN ge 10">
<set_value name="$absN" exact="$absN / 10" />
<set_value name="$mag" operation="add" />
</do_while>
<do_while value="$absN lt 1 and $absN != 0">
<set_value name="$absN" exact="$absN * 10" />
<set_value name="$mag" operation="subtract" />
</do_while>
<!-- shift = d - mag - 1 -->
<set_value name="$shift" exact="$d - $mag - 1" />
<set_value name="$factor" exact="10 ^ $shift" />
<do_if value="@$direction == 'up'">
<!-- Scale up -->
<set_value name="$scaled" exact="$number * $factor" />
<set_value name="$intPart" exact="($scaled)i" />
<!-- Round up manually -->
<do_if value="$scaled == $intPart">
<set_value name="$return" exact="$scaled / $factor" />
</do_if>
<do_else>
<set_value name="$return" exact="if $number ge 0 then ($intPart + 1) / $factor else ($intPart - 1) / $factor" />
</do_else>
</do_if>
<do_elseif value="@$direction == 'down'">
<set_value name="$scaled" exact="$number * $factor" />
<set_value name="$return" exact="if $scaled lt 0 and $scaled != ($scaled)i then (($scaled)i - 1) / $factor else ($scaled)i / $factor" />
</do_elseif>
<do_else>
<!-- Round -->
<set_value name="$return" exact="if $number ge 0 then ($number * $factor + 0.5)i / $factor else ($number * $factor - 0.5)i / $factor" />
</do_else>
<return value="$return" />
</actions>
</library>
Decimal Places Version:
Rounds by decimal places. Just like Excel's Round, RoundUp, RoundDown
Code: Select all
<run_actions ref="Round" result="$rounded">
<param name="number" value="1234.567" />
<param name="d" value="-1" />
</run_actions>
Code: Select all
<run_actions ref="Round" result="$rounded">
<param name="number" value="0.01987" />
<param name="d" value="3" />
<param name="direction" value="'down'" />
</run_actions>
Code: Select all
<library name="Round" purpose="run_actions">
<params>
<param name="number" />
<param name="d" />
<param name="direction" default="null" /> <!-- optional: 'up' or 'down' -->
</params>
<actions>
<!-- Just calculate the scaling factor for decimal places -->
<set_value name="$factor" exact="10 ^ $d" />
<do_if value="@$direction == 'up'">
<set_value name="$scaled" exact="$number * $factor" />
<set_value name="$intPart" exact="($scaled)i" />
<do_if value="$scaled == $intPart">
<set_value name="$return" exact="$scaled / $factor" />
</do_if>
<do_else>
<set_value name="$return" exact="if $number ge 0 then ($intPart + 1) / $factor else ($intPart - 1) / $factor" />
</do_else>
</do_if>
<do_elseif value="@$direction == 'down'">
<set_value name="$scaled" exact="$number * $factor" />
<set_value name="$return" exact="if $scaled lt 0 and $scaled != ($scaled)i then (($scaled)i - 1) / $factor else ($scaled)i / $factor" />
</do_elseif>
<do_else>
<!-- Round to nearest -->
<set_value name="$return" exact="if $number ge 0 then ($number * $factor + 0.5)i / $factor else ($number * $factor - 0.5)i / $factor" />
</do_else>
<return value="$return" />
</actions>
</library>