[Library] Round, RoundUp, RoundDown

The place to discuss scripting and game modifications for X4: Foundations.

Moderators: Scripting / Modding Moderators, Moderators for English X Forum

h2o.Ava
Posts: 349
Joined: Sun, 12. Oct 08, 04:04
x4

[Library] Round, RoundUp, RoundDown

Post by h2o.Ava »

Two versions. One for sig digits, the other by decimal places (like Excel).

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>
1234.567 → rounded to 3 sig digits = 1230

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>
0.01987 → rounded down to 2 sig digits = 0.019

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>
1234.567 → rounded to -1 decimal places = 1230

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>
0.01987 → rounded down to 3 decimal places = 0.019

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>
Last edited by h2o.Ava on Sun, 6. Apr 25, 10:52, edited 3 times in total.
h2o.Ava
Posts: 349
Joined: Sun, 12. Oct 08, 04:04
x4

Re: [Library] Round, RoundUp, RoundDown

Post by h2o.Ava »

Mmm... maybe I should make one that is number of decimal places instead of significant digits.
Last edited by h2o.Ava on Sun, 6. Apr 25, 10:51, edited 1 time in total.
h2o.Ava
Posts: 349
Joined: Sun, 12. Oct 08, 04:04
x4

Re: [Library] Round, RoundUp, RoundDown

Post by h2o.Ava »

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>
1234.567 → rounded to -1 decimal places = 1230

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>
0.01987 → rounded down to 3 decimal places = 0.019

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>

Return to “X4: Foundations - Scripts and Modding”