Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Negative zero and float to string issues

Epilort Byrne
Registered User
Join date: 6 Jul 2004
Posts: 30
06-06-2007 06:59
Hi. I am making a game that uses up and down arrows to control the budget for a certain category and also updates the amount of funds available in the bank. The balance and price are displayed through llSetText and the floats (that hold the budget and balance) are incremented and decremented by the arrows in 0.10 intervals. My problem is that when moving from 2.70 to 2.80, the the budget float cast to string instead reads 2.79. When I go back down to zero, it is sometimes a negative zero, which isn't proper for displaying a price. How can I alleviate these issues if possible? I am using this function I found in the Wiki to display the floats:

CODE

string fixed_precision(float input, integer precision)
{
if((precision = (precision - 7 - (precision < 1))) & 0x80000000)
return llGetSubString((string)input, 0, precision);
return (string)input;
}


Thanks!
Learjeff Innis
musician & coder
Join date: 27 Nov 2006
Posts: 817
06-06-2007 07:32
Welcome to floating point. The problem here is that 1/10 is a repeating fraction in binary.

The "negative zero" you're encountering is actually a small negative number that is so small the significant digits don't show up using the cast-to-string conversion. (Well, negative zero is possible to represent in floating point, IIRC, but you don't really have to worry about it in ordinary circumstances.)

The best solution is probably to write a function that converts amounts to strings and only prints two digits past the decimal (with rounding). Something like this:

CODE

string amt2str(float amt)
{
integer dollars = (integer)amt;
integer cents = (integer)((amt - (float)dollars) * 100.0);

if (cents < 10) {
return (string)dollars + ".0" + (string)cents;
}
return (string)dollars + "." + (string)cents;
}


There is probably a more elegant way to code this in LSL. I didn't test the code, so bugs are possible.
Dopel Dollinger
Registered User
Join date: 25 May 2007
Posts: 14
06-06-2007 07:50
I am not sure what you mean by a negative zero, since there is no such thing. Zero is not negative or positive, it is just zero. The function you posted takes in a float and returns a string representation of that number with the given pricision. What are the actual values of the arguments you are passing to this function? Did you write this function, because I get a syntax error when I run it.

if((precision = (precision - 7 - (precision < 1))) & 0x80000000)

You are applying a boolean operation (precision < 1) to a subtraction of ints. This is equivilent to saying 2 - 7 - True.
RobbyRacoon Olmstead
Red warrior is hungry!
Join date: 20 Sep 2006
Posts: 1,821
06-06-2007 08:23
From: Dopel Dollinger
I am not sure what you mean by a negative zero, since there is no such thing. Zero is not negative or positive, it is just zero. The function you posted takes in a float and returns a string representation of that number with the given pricision. What are the actual values of the arguments you are passing to this function? Did you write this function, because I get a syntax error when I run it.

if((precision = (precision - 7 - (precision < 1))) & 0x80000000)

You are applying a boolean operation (precision < 1) to a subtraction of ints. This is equivilent to saying 2 - 7 - True.


It's actually not uncommon to get a negative zero value in programming, since it's just a zero value with the sign bit on. Some dev environments have built-in checks for that sort of thing, some don't.

As for the function above that causes you syntax errors, I've seen the wiki example that was mentioned by the OP and I believe that the "precision < 1" portion of that expression is supposed to be a shift-left operation: "precision << 1". Maybe the forums messed it up, or maybe the OP copied it wrong, I don't know, but I'm pretty sure that a shift-left is what's intended.

.
_____________________
Dopel Dollinger
Registered User
Join date: 25 May 2007
Posts: 14
06-06-2007 08:48
Learn something hew every day.
http://en.wikipedia.org/wiki/%E2%88%920_(number)
Thanks Robbie!
Epilort Byrne
Registered User
Join date: 6 Jul 2004
Posts: 30
06-06-2007 08:57
"The problem here is that 1/10 is a repeating fraction in binary."

Dropped my last CS course right as we were getting to floating point representation. Will have to retake that one when I go back. Anyway, thanks for the explanation and help!

also...

"What are the actual values of the arguments you are passing to this function? Did you write this function, because I get a syntax error when I run it."

True is 1 and False is 0...I'm not sure how you got a syntax error.

llSay(0, (string)((1 < 5) + ( 2 < 5))); // = 2
Epilort Byrne
Registered User
Join date: 6 Jul 2004
Posts: 30
06-06-2007 09:26
Learjeff:

The function you supplied compiles but still displays inaccurately (or not how I want it to). I don't know if it's possible using 10 cent increments.
Newgate Ludd
Out of Chesse Error
Join date: 8 Apr 2005
Posts: 2,103
06-06-2007 10:33
From: Epilort Byrne
Learjeff:

The function you supplied compiles but still displays inaccurately (or not how I want it to). I don't know if it's possible using 10 cent increments.


Switch to using integer maths.
_____________________
I'm back......
Lex Neva
wears dorky glasses
Join date: 27 Nov 2004
Posts: 1,361
06-06-2007 10:56
From: Newgate Ludd
Switch to using integer maths.


In other words, store the number of cents in an integer, not a floating-point number of dollars.
Epilort Byrne
Registered User
Join date: 6 Jul 2004
Posts: 30
06-06-2007 11:39
perfect thanks

For some reason this doesn't work for the bank part of the script. It starts off at 2000 and displays its string with this:

string fixed_precision(float input, integer precision)
{
if((precision = (precision - 7 - (precision < 1))) & 0x80000000)
return llGetSubString((string)input, 0, precision);
return (string)input;
}

string cents_to_dollars_str(integer cents)
{
return fixed_precision(((float)cents / 100),2);
}

...return .01 lower than its supposed to with calls to

cents_to_dollars_str(1980);
cents_to_dollars_str(1930);

The other script work okay with the same calls...?
Learjeff Innis
musician & coder
Join date: 27 Nov 2006
Posts: 817
06-06-2007 18:47
From: Epilort Byrne
Learjeff:

The function you supplied compiles but still displays inaccurately (or not how I want it to). I don't know if it's possible using 10 cent increments.


That isn't very helpful. I can't read your mind, so you're on your own.

If you want help, post output you get, tell us what the input was, and what's wrong with the output.
Epilort Byrne
Registered User
Join date: 6 Jul 2004
Posts: 30
06-07-2007 06:48
I meant displays inaccurately just like the original function I was using (though with surprisingly less precision). Anyway the solution is to keep track of everything in cents which is better for display and also passing around in link messages.