How to reliably format a floating point number to a specified number of decimal places in Haxe

StackOverflow https://stackoverflow.com/questions/23689001

  •  23-07-2023
  •  | 
  •  

Question

I was wondering if there is a reliable way to convert a Float x in haxe to a String with a specified number of decimal places, e.g. 3.

A straightforward method is to first convert x to a string representation, and then trim everything after a given number of characters after the decimal point ., as shown here. However, what happens if some platform shows a number like 0.0111 as 1.11e-2?

I can't seem to find a printf in haxe either, which would allow me to format the number the right way. I was wondering what's the best practice for doing this in haxe.

I wanted to obtain strings in the result, because in some systems, floating point numbers gives you, e.g., 0.19999.. from 2/10.0. And it would be inaccurate just to truncate certain number of characters after the decimal point.

Was it helpful?

Solution

public static function floatToStringPrecision(n:Float, prec:Int){
  n = Math.round(n * Math.pow(10, prec));
  var str = ''+n;
  var len = str.length;
  if(len <= prec){
    while(len < prec){
      str = '0'+str;
      len++;
    }
    return '0.'+str;
  }
  else{
    return str.substr(0, str.length-prec) + '.'+str.substr(str.length-prec);
  }
}

Round may fail on big numbers(> MAX_INT) on some platforms, so for that case you need your own round function.

OTHER TIPS

If you can settle for just rounding to a certain precision, then you could use something simple like this.

/**
    Uses Math.round to fix a floating point number to a set precision.
**/
public static function round(number:Float, ?precision=2): Float
{
    number *= Math.pow(10, precision);
    return Math.round(number) / Math.pow(10, precision);
}

Taken from Franco Ponticelli's THX library: https://github.com/fponticelli/thx/blob/master/src/Floats.hx#L206

If you want something more like PrintF, but light weight, maybe take a look at the relevant code and pull out just the bit to do with printing floats to a certain precision. There is a lot of other functionality in there that you could safely ignore if you only want this one feature.

Here are optimized versions. The general function is around 20% faster and the specific version for 3 decimals is 50% faster. Avoids creating strings and string concatenations as posible, and also avoids the division for precision issues

public static function floatToStringPrecision(n:Float,prec:Int)
{
    if(n==0)
        return "0." + ([for(i in 0...prec) "0"].join("")); //quick return

    var minusSign:Bool = (n<0.0);
    n = Math.abs(n);
    var intPart:Int = Math.floor(n);
    var p = Math.pow(10, prec);
    var fracPart = Math.round( p*(n - intPart) );
    var buf:StringBuf = new StringBuf();

    if(minusSign)
        buf.addChar("-".code);
    buf.add(Std.string(intPart));

    if(fracPart==0)
    {
        buf.addChar(".".code);
        for(i in 0...prec)
            buf.addChar("0".code);
    }
    else 
    {
        buf.addChar(".".code);
        p = p/10;
        var nZeros:Int = 0;
        while(fracPart<p)
        {
            p = p/10;
            buf.addChar("0".code);
        }
        buf.add(fracPart);
    }
    return buf.toString();
}

The a specific function for the case prec=3

public static function floatToStringPrecision3(n:Float)
{
    if(n==0)
        return "0.000";

    var minusSign:Bool = (n<0.0);
    n = Math.abs(n);
    var intPart:Int = Math.floor(n);
    var p:Float = 1000.0; //pow(10, 3)
    var fracPart = Math.round( p*(n - intPart) );
    var buf:StringBuf = new StringBuf();

    if(minusSign)
        buf.addChar("-".code);
    buf.add(Std.string(intPart));
    if(fracPart==0)
         buf.add(".000");
    else 
    {
        if(fracPart<10)
            buf.add(".00");  
        else if(fracPart<100)
            buf.add(".0"); 
        else
            buf.add("."); 
        buf.add(fracPart);
    }
    return buf.toString();
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top