Haxe Code Cookbook
Haxe programming cookbookAbstract typesRounded Float as abstract type

Rounded Float as abstract type

This abstract type is based on the underlying Float type, but whenever it is converted back to an actual Float it is rounded to avoid the famous rounding errors occuring in floating point aritmetics.

Please note that this example doesn't solve the rounding error problem - it just covers it by rounding the errors away. This shouldn't be used in situations where accumulated errors might cause critical problems - for example in financial calculations. For those cases, something like Franco Ponticelli's thx.Decimal should be used instead.

abstract RFloat(Float) from Float {
  inline function new(value : Float)  
    this = value;
  
  // The following rounds the result whenever converted to a Float
  @:to inline public function toFloat():Float  {
    return roundFloat(this);
  }
 
  @:to inline public function toString():String {
    return Std.string(toFloat());
  }

  // The number of zeros in the following valuer
  // corresponds to the number of decimals rounding precision
  static inline var multiplier = 10000000;
    
  static inline function roundFloat(value:Float):Float
    return Math.round(value * multiplier) / multiplier;
}

Usage

// Standard float gives a result with rounding error
var f:Float = 2.0 - 1.1;
trace(f); // 0.8999999999999999

// RFloat abstract rounds the error away
var rf:RFloat = 2.0 - 1.1;
trace(rf); // 0.9

A cool trick is to let the compile time type check force a cast to RFloat only in the moment when it's actually needed:

// We define the variable as a standard float
var f:Float = 2.0 - 1.1;
// In the moment we need the rounded version, we use the '(f:RFloat)' syntax to force a cast to 'RFloat':
trace((f:RFloat)); // 0.9

Learn about Haxe Abstracts here: https://haxe.org/manual/types-abstract.html


Contributors:
Last modified:
Created:
Category:  Abstract types