displaying Decimal numbers

Monkey Forums/Monkey Programming/displaying Decimal numbers

C10B(Posted 2012) [#1]
Hi,

I am using floats for numbers during calculations, but want to round them up when I want to display them. So 10.120000000099 looks like 10.1

I found no rounding function built in, but found this online (which is fairly standard practice for rounding)

Function Round:Float(N:Float, DecimalPlaces:Int)
Return Float(Int(N * Pow(10.0,DecimalPlaces))) / Pow(10.0,DecimalPlaces)
End Function

The trouble is that the returned number is still a float! So yes, 10.12 might get rounded nicely to 10.1, but when I display it it sometimes displays as 10.10000000094324.

How can I display a number with a decimal place without the grief that displaying floats can give?

Many thanks


DGuy(Posted 2012) [#2]
Off the top of my head, something like the below should work:

1) Convert rounding result to a string

2) Split on decimal point into whole and fractional parts

3) Recombine whole + "." + fractional[..DecimalPlaces]


Jesse(Posted 2012) [#3]
this should work(untested):
n:float = 10.12000099

n = (int(n*10)/10.0)


That function in your post works for me also.


NoOdle(Posted 2012) [#4]
Tested both versions and neither round the decimal places correctly, they only display x places. I spent a few minutes racking my brain and came up with this, it rounds correctly to any number of decimal places displaying a float. (HTLM5 tested only) Possibly could be written more elegantly but it works...

10.23 will round to 10.2
10.25 will round to 10.2
10.26 will round to 10.3

[monkeycode]
Function Round : Float( value : Float, places : Int = 1 )
Local div : Float = Pow( 10.0, places )
Local a : Float = value * div
Local b : Float = Floor( a )
If a - b <= 0.5 Return b / div
Return Ceil( a ) / div
End Function
[/monkeycode]
If anyone knows a shorter/cleaner way please can you post the code, I've always wondered how to do this.


C10B(Posted 2012) [#5]
Hi, both examples though still return a float. This is still a problem and numbers can sometimes look wrong (ie 10.120000000002345) even after rounding, particularly when output to Windows or iOS rather than to HTML5

I think returning a string is the only option in the absence of a decimal type.


NoOdle(Posted 2012) [#6]
For other targets you can probably still use the Round function but then trim the string to x decimal places as well to hide the float trailing errors....


Beaker(Posted 2012) [#7]
Function Format:String(num:Float, places:Int, removeZeros:Bool=True)
	Local txt:String = String(num)
	Local pointPos:Int = txt.Find(".")
	If pointPos = -1 Return txt
	txt = txt[..pointPos+places+1]
	If removeZeros
		While txt[txt.Length-1] = 48
			txt = txt[..txt.Length-1]
		End
		If txt[txt.Length-1] = 46 txt = txt[..txt.Length-1]
	End
	Return txt
End



ziggy(Posted 2012) [#8]
As long as the function returns a float, it won't be able to properly display rounded floats.
Example:
Function Main()
	Print Round(Sqrt(2), 1)
End
Function Round:Float(value:Float, places:Int = 1)
 	Local div : Float = Pow( 10.0, places )
 	Local a : Float = value * div
 	Local b : Float = Floor( a )
 	If a - b <= 0.5 Return b / div
 	Return Ceil( a ) / div
End Function

Output:
1.3999999999999999

A display-round function, in my opinion, shoud return a formatted string with internal rounding done in a way it handles the float rounding precission properly, instead of bypassing it or, even worse, making it happen a lot before, like in the sample I've just shown.

EDIT:
I suggest this implementation (may be improved):

[monkeycode]Function Round:String(value2:Float, places:Int = 1, decSymbol:Int = "."[0])

'We convert the number to a truncated version of it, using a integer representation of places + 1 chars:
Local rounding:Int = math.Abs(value2 * math.Pow(10, places + 1))

'We round the value, according to latest character:
If rounding Mod 10 >= 5
rounding += 10
EndIf

'We convert this result to a String, knowing the number of digits and knowing where to place the decimal symbol separator:
Local result:String = rounding

'If the number begins with a dot, we put the 0, so it gets 0.45 instead of .45 wich is a lot ugglier on display:
If result.Length = places + 1 Then result = "0" + result

'We create a buffer to store the resulting rounded number string:
Local buffer:Int[] = New Int[result.Length]

'We iterate throug original number, putting the decimal separator in place, and therefore ignoring latest digit (places + 1) so it gets the correct number after rounding.
For Local i:Int = 0 Until buffer.Length
If i < buffer.Length - places - 1 Then
buffer[i] = result[i]
ElseIf i = buffer.Length - places - 1
buffer[i] = decSymbol
Else
buffer[i] = result[i - 1]
End
End

'We return the generated rounded number string, according to original number sign:
If value2 >= 0 Then
Return String.FromChars(buffer)
Else
Return "-" + String.FromChars(buffer)
EndIf
End[/monkeycode]


xAD(Posted 2013) [#9]
or x10 and call it an int