Rounding problem

So, I am using the round variable so that things display in a nicer way. Basically, if I divide 4 by 7 is should be 57.14. The round variable brings this down to… 56.99999999999999%. I am a bit confused… has anybody had this problem before? Any ideas how to solve it?

This is what is diplayed:

HP 4/7: 56.99999999999999%

I’ve never seen this problem.

One thought is if the initial division generates loads of decimal points then it struggles to correctly resolve them back to a round number. So it gives you all the 9s.

Try rounding the result of the round. Might be a viable workaround.

Is it possible to use integers types in choicescript? I’m assuming this a problem with how floats work and their available data.

Here is an example: javascript - floating point 0.2 + 0.1 rounding error - Stack Overflow

It has to do in part with JavaScript’s float point number and in part with processor limitation.

ChoiceScript relays all its arithmetic operations to the underlying JavaScript engine and uses the same primitives. ChoiceScript doesn’t have an integer type, only a number type.

I don’t know how much you’re interested into technical jargon, but here are two articles explaining what’s going on:

JavaScript Corner: Math and the Pitfalls of Floating Point Numbers

What Every JavaScript Developer Should Know About Floating Points


I whipped up this solution. This will round 0.5 or greater to 1, otherwise, return only the integer part (round down). You’ll need a return variable to capture the result.

*comment __startup.txt__
*create return 0

*commnet __utils.txt__
*label round
*params number
*temp floatPoint (number modulo 1)
*temp integerPart (number - floatPoint)
*if (floatPoint >= 0.5)
	*set integerPart  +1
*set return integerPart
*return

Then call it as usual:

*gosub_scene utils round 57.14
${return}

It should print 57.


@CJW, maybe we could add this to the cslib math module or number module. :thinking:

3 Likes

I tried rounding the round… but it didn’t seem to work… I guess I could try rounding a third time, but any other solutions?

1 Like

I’m a little confused, I assume there is a missing lead 0 in the example?

i.e. 4/7 = 0.5714?
Not 4/7 = 57.14?

Though the round() function should always return an integer (whole number), so I’m not sure how you’re getting 56.99999999999999. Apologies if I’m missing something.

If this is a solution to be able to round to near decimal points (rather than the nearest whole integer), then I think that would be a good addition to the math module. Maybe adding ceil and floor too?
Not sure it solves what’s going on here, but a patch would be great :slight_smile:

2 Likes

I think the original expression might have been:

(4 / 7) * 100

I admit I did not test the native round function, but I remember ChoiceScript does have a problem with float point numbers.

About precision rounding, I believe it would be a matter of multiplying by the precision factor and then diving again.

*temp precisionFactor 100
*temp roundNumber (number * precisionFactor) 
*set roundNumber round(roundNumber)
*set roundNumber (roundNumber / precisionFactor) 
4 Likes

That would make a lot more sense! Still, round would turn that into 57. ChoiceScript’s round just passes the value to Math.round (which, as far as I’m aware, should only ever return a whole number).

4 Likes

I don’t know how you wrote it but here’s mine:

sweet 57 printed out

Huh. I could have sworn that Math.round() took an optional second argument for decimal places.

Still scratching my head over this one, but somehow I managed to fix it… mmmmmmm

It seems like Math.round() is a better solution, but it is not! In some cases it will NOT round correctly. Also, toFixed() will NOT round correctly in some cases.

To correct the rounding problem with the previous Math.round() and toFixed(), you can define a custom JavaScript rounding function that performs a “nearly equal” test to determine whether a fractional value is sufficiently close to a midpoint value to be subject to midpoint rounding. The following function return the value of the given number rounded to the nearest integer accurately.

Number.prototype.roundTo = function(decimal) {
  return +(Math.round(this + "e+" + decimal)  + "e-" + decimal);
}

var num = 9.7654;
console.log( num.roundTo(2)); //output 9.77
1 Like