; ; Various FP rounding functions ; ; see https://en.wikipedia.org/wiki/Rounding for explanations ; ; jchd 2018/12 ; ; Round down towards -Inf Func _Round_Down($f) Return Floor($f) EndFunc ; Round up towards +Inf Func _Round_Up($f) Return Ceiling($f) EndFunc ; Round towards zero Func _Round_ToZero($f) Return Int($f) EndFunc ; Round away from zero Func _Round_FromZero($f) Return _Sign($f) * Ceiling(Abs($f)) EndFunc ; Round half down towards -Inf Func _Round_HalfDown($f) Return Ceiling($f - 0.5) EndFunc ; Round half up towards +Inf Func _Round_HalfUp($f) Return Floor($f + 0.5) EndFunc ; Round half towards zero Func _Round_HalfToZero($f) Return _Sign($f) * Ceiling(Abs($f) - 0.5) EndFunc ; Round half away from zero Func _Round_HalfFromZero($f) Return _Sign($f) * Floor(Abs($f) + 0.5) EndFunc ; Round half to even Func _Round_HalfEven($f) Local $i = Int($f) Return (Abs($f - $i) <> 0.5 ? Round($f, 0) : $i + Mod($i, 2)) EndFunc ; Round half to odd Func _Round_HalfOdd($f) Local $i = Int($f) Return (Abs($f - $i) <> 0.5 ? Round($f, 0) : (Mod($i, 2) ? $i : $f + 0.5 * _Sign($f) )) EndFunc ; Round alternating Func _Round_Alternate($f) Static $dice = Random(0, 1, 1) $dice = BitXOR($dice, 1) Return (Abs($f - Int($f)) <> 0.5 ? Round($f, 0) : $f + ($dice ? -0.5 : 0.5)) EndFunc ; Round random Func _Round_Random($f) Return (Abs($f - Int($f)) <> 0.5 ? Round($f, 0) : $f + (Random(0, 1, 1) ? -0.5 : 0.5)) EndFunc ; Round stochastic (special use) Func _Round_Stochastic($f) Local $floor = Floor($f) Return (IsInt($f) ? $f : ($floor + (Random() < Abs($f - $floor)))) EndFunc ; helper function Func _Sign($f) Return ($f > 0 ? 1 : ($f < 0 ? -1 : 0)) EndFunc ; ============================ ; ; demo code ; ; compare to the table in the wiki article Local $aTest = [ 1.8, 1.5, 1.2, 0.8, 0.5, 0.2, -0.2, -0.5, -0.8, -1.2, -1.5, -1.8 ] ConsoleWrite(@LF & "Results of deterministic rounding methods" & @LF) ConsoleWrite("Value Down Up ToZero FromZero HalfDown HalfUp HalfToZero HalfFromZero HalfEven HalfOdd" & @LF) For $f In $aTest ConsoleWrite(StringFormat("% 3.1f % 2.0f % 2.0f % 2.0f % 2.0f % 2.0f % 2.0f % 2.0f % 2.0f % 2.0f % 2.0f\n", _ $f, _Round_Down($f), _Round_Up($f), _Round_ToZero($f), _Round_FromZero($f), _Round_HalfDown($f), _ _Round_HalfUp($f), _Round_HalfToZero($f), _Round_HalfFromZero($f), _Round_HalfEven($f), _Round_HalfOdd($f))) Next ConsoleWrite(@LF & "Average results for 10,000 runs of randomized rounding methods" & @LF) ; Average for 10000 runs ConsoleWrite("Value Alternate Random Stochastic" & @LF) For $f In $aTest ConsoleWrite(StringFormat("% 3.1f % 5.3f % 5.3f % 5.3f\n", _ $f, _Avg10k(_Round_Alternate, $f), _Avg10k(_Round_Random, $f), _Avg10k(_Round_Stochastic, $f))) Next ConsoleWrite(@LF) ; used for averaging demo Func _Avg10k($fct, $f) Local $sum For $i = 1 To 10000 $sum += $fct($f) Next Return $sum / 10000 EndFunc