Floats giving me headache!
|
Omen Torgeson
Registered User
Join date: 12 Jun 2004
Posts: 155
|
01-15-2005 19:55
I'm reading a value (say, 1.5) from a notecard and using it in a script for math functions. I have no problem reading or using the amount from the notecard, the only annoying problem is when I print the float to screen. It shows up as: 1.5000000000 I'd really like to get rid of the extra nonsense (the zeros) on the end and only print the real data. Object whispers: "Your float is 1.5!" ----> NOT ----> Object whispers: "Your float is 1.50000000000000, fool! Hahahahahaha!"  I can't find a math function that will fix this. This is an aesthetical problem more than anything else. I just hate the annoying 0000000 at the end when I print to screen. Anyone know a way to get around this? Thanks.
_____________________
Max Schreck: "I feed like an old man pees -- sometimes all at once, sometimes drop by drop."
-Shadow of the Vampire
|
Upshaw Underhill
Techno-Hobbit
Join date: 13 Mar 2003
Posts: 293
|
01-15-2005 21:22
something along the lines of:
float i = 1.5; llWhisper(0,"The value of i is " + llGetSubString((string)i,0, llSubStringIndex((string)i,".") + 1));
or something fairly close to this bundled preferably into a function.  L8r, UU
|
Carnildo Greenacre
Flight Engineer
Join date: 15 Nov 2003
Posts: 1,044
|
01-15-2005 22:44
Somewhere in the scripting library is a LSL implementation of the C sprintf() function. It takes a great deal of memory, and is slow to work, but it gives you incredible control of formatting.
_____________________
perl -le '$_ = 1; (1 x $_) !~ /^(11+)\1+$/ && print while $_++;'
|
Jeffrey Gomez
Cubed™
Join date: 11 Jun 2004
Posts: 3,522
|
01-16-2005 12:56
Upshaw has the right idea. While I hate to be nitpicky, though, "integer i = 1.5;" evaluates to 1. Just a slight typo there; I think you wanted "float." Additionally, this is what I think you wanted, Omen: float i = 1.5;
string whole = llGetSubString((string)i,0,llSubStringIndex((string)i,".") - 1); string remainder = llGetSubString((string)i, llSubStringIndex((string)i, "."),llStringLength((string)i) - 1);
string current = "0"; integer count = llStringLength(remainder);
while(current == "0") { count--; //I usually just replace this with count -= 1; just in case current = llGetSubString(remainder,count,count); }
if(count > 0) remainder = llGetSubString(remainder,0,count); else remainder = ""; //in case we have a whole number stored as a float
llWhisper(0,"Your number is " + whole + remainder);
While Upshaw's will give you basic code that assumes you know the number of significant digits you'll need, the above should give you any float minus garbage zeros at the end. I had to write it this way because llSubStringIndex returns the first instance of a searched sub string, so had you typed "10.5" or "1.501" - that would not have worked so well. Note my code is also untested, so if I screwed up, feel free to peg me for it. 
|
Lex Neva
wears dorky glasses
Join date: 27 Nov 2004
Posts: 1,361
|
01-16-2005 15:58
Fortunately, 1.5 turns cleanly into a binary number. Unfortunately, other fractions that we think are nice and simple are not easily represented internally in a computer. The result is that cleaning off those trailing zeroes won't always work, because sometimes you'll have a 1 right at the end. You're going to have to round the number to a certain number of decimal places. Let me try my hand at this...
// round the number to the given number of decimal places
round(float number, integer places) { integer i; float shifted; integer rounded; string unshifted;
if (places == 0) return llRound(number);
shifted = number * llPow(10.0, (float)places);
rounded = llRound(shifted);
unshifted = (string)((float)rounded / llPow(10.0, (float)places));
return llGetSubstring(unshifted, 0, llSubStringIndex(unshifted, ".") + places); }
Ok, this hasn't been tested at all, but I think it works right. Here's what it does. Say you give it the number 12.34567 and tell it you want it to give you 3 decimal places. It multiplies the number by 1000 (that's that llPow() line) to get 12345.67. Then it uses llRound() to round off that decimal part. I really wish I didn't have to do this multiply/round business, but llRound() will only round off the entire decimal. Anyway, this saves me from having to do my own rounding. So now I'm left with 12346 as an integer, which I then divide (as floats) by 1000 to get me back to 12.346. That is, I'm left with approximately 12.346... there may be a fraction way at the end. So now I convert it to a string and chop off the whole part and the right number of decimal places, and I'm all set. Note, this may return 1.200 if you do round(1.2,3). That's just the way it works. You can use jeffrey's code now to chop off those zeroes safely. That said, I'm heading over to the feature suggestions forum to ask for some more advanced rounding capabilities.
|
Tread Whiplash
Crazy Crafter
Join date: 25 Dec 2004
Posts: 291
|
Brute-force method...
01-16-2005 16:47
Well, I haven't tried this; but I believe it would work just fine (maybe slow, though): Imagine we have a float called "my_float". If you know how many whole-number-digits are in your float, take that number "n", add x+1, where "x" is the number of digits after the decimal point that you want. Then you simply do this: string num_string = llGetSubString((string)my_float, 0, n+x+1);
Do your displays with the string. If you need to use this "rounded" number, cast it back to a float - although be aware you're going to be putting rounding errors into your calculations.  If you do not know the number of digits you need, you can further convert the string to a list: list num_list = llParseString2List((string)my_float, ["."],[]);
string num_string = llList2String(num_list,0) + "." + llGetSubString(llList2String(num_list,1), 0, decimal_digits);
...Where "decimal_digits" is an integer with the number of digits you want to include, after the decimal point. Enjoy, --Noel "HB" Wade (Tread Whiplash)
|
Omen Torgeson
Registered User
Join date: 12 Jun 2004
Posts: 155
|
01-16-2005 17:29
Thank you so much, everyone, for the responses! As a temp fix for this, before any replies came into the forum, I did the following as an ugly but quick fix: When accessing the notecard I script-read the line with the # on it, and cast the infomation into two types. string numprint = notedata; float nummath = notedata; Then just used both types for its specific use. IE: llSay(0, numprint + " is your number, sans zeros, baby!"  ; And used the float nummath for the actual math functions in the script. It worked...but I knew I wanted a better solution than that, and you guys have provided several. Thank you! I'm going to try implement these next time I'm in world and tweaking my script. 
_____________________
Max Schreck: "I feed like an old man pees -- sometimes all at once, sometimes drop by drop."
-Shadow of the Vampire
|
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
|
01-16-2005 22:29
/15/28/28006/1.htmlA little bit on the overkill side but it will do what you want.
_____________________
Truth is a river that is always splitting up into arms that reunite. Islanded between the arms, the inhabitants argue for a lifetime as to which is the main river. - Cyril Connolly
Without the political will to find common ground, the continual friction of tactic and counter tactic, only creates suspicion and hatred and vengeance, and perpetuates the cycle of violence. - James Nachtwey
|