Problem with returning a real in my rounding number routine...

Hello!

I have been successful in creating a routine that returns a rounded number that pleases me, but the problem is that it only returns a string. Even though it is submitted as a real, I have been unsuccessful in returning it in the same type. Does anyone have an idea?

Here is the fully functional routine by the way:

on roundThisNumber_toThisDecimalPlaces_withThisRoundingMethod_(number_to_round, decimal_places, rounding_method)
		(*
		1 = NSNumberFormatterRoundCeiling = Round up to next larger number with the proper number of digits after the decimal separator.
		2 = NSNumberFormatterRoundFloor = Round down to next smaller number with the proper number of digits after the decimal separator.
		3 = NSNumberFormatterRoundDown = Round down to next smaller number with the proper number of digits after the decimal separator.
		4 = NSNumberFormatterRoundUp = Round the last digit, when followed by a 5, toward an even digit (.25 -> .2, .35 -> .4)
		5 = NSNumberFormatterRoundHalfEven = Round up to next larger number with the proper number of digits after the decimal separator.
		6 = NSNumberFormatterRoundHalfDown = Round down when a 5 follows putative last digit.
		7 = NSNumberFormatterRoundHalfUp = Round up when a 5 follows putative last digit.
		*)
		set roundingMethods to {¬
			current application's NSNumberFormatterRoundCeiling, ¬
			current application's NSNumberFormatterRoundFloor, ¬
			current application's NSNumberFormatterRoundDown, ¬
			current application's NSNumberFormatterRoundUp, ¬
			current application's NSNumberFormatterRoundHalfEven, ¬
			current application's NSNumberFormatterRoundHalfDown, ¬
			current application's NSNumberFormatterRoundHalfUp}
		
		set theRoundingFormat to "0.##" as string --default decimal places format
		if rounding_method < 1 and rounding_method > 7 then set rounding_method to 7 --make sure we have a valid default rounding method
		
		if (decimal_places as integer) = 0 then
			set theRoundingFormat to "0" as string
		else if (decimal_places as integer) > 0 then
			set theRoundingFormat to "0." as string
			repeat with myCount from 1 to (decimal_places as integer)
				--set theFormat to theFormat's stringByAppendingString_("#")
				set theRoundingFormat to (theRoundingFormat & "#") as string
			end repeat
		end if
		
		set number_formatter to current application's NSNumberFormatter's alloc()'s init()
		tell number_formatter
			setFormat_(theRoundingFormat)
			setRoundingMode_(item rounding_method of roundingMethods)
			set theRoundedValueAsString to stringFromNumber_(number_to_round)
		end tell
		return (theRoundedValueAsString) as string
end roundThisNumber_toThisDecimalPlaces_withThisRoundingMethod_

and you call it like this:

my roundThisNumber_toThisDecimalPlaces_withThisRoundingMethod_(123.456789, 2, 7)

returns : “123.46”

Browser: Safari 531.22.7
Operating System: Mac OS X (10.6)

Have you tried using numberFromString:?

BTW, this routine is based on your book, on page 111, “Other Useful Classes” :slight_smile: … Thanks, great book!

Yep, I did try this, but the thing is it creates an NSNumber, and when I try to coerce it to a real in AS, it does something like 25.27 → 25.27000045776367 … which is not really what I intended to have. Tried not coercing it, but it doesn’t work of course. Also, coercing to number creates an error, which made me decide to always use real from now on, seems like number doesn’t work in ASOC.

So this works:

set theRoundedValueAsString to stringFromNumber_(number_to_round)
set theRoundedValueAsReal to numberFromString_(theRoundedValueAsString) as real

with the result I mentioned before (25.27 → 25.27000045776367). If I don’t coerce it to real and log the result, the number is 25.27. If I log the class of the resulting variable, it says “<NSAppleEventDescriptor: ‘doub’>”, thus it probably is a double value…

Should I use an instance method of NSNumber to extract the correct number from the NSNumber value? Something like doubleValue or decimalValue ?

Seems like number coercion in ASOC is a bit tricky…

Browser: Safari 531.22.7
Operating System: Mac OS X (10.6)

It’s a difficult area – let me have a think. At this stage all I can suggest is getting text and coercing it to a real in AppleScript.

The problem with numbers is that AS and Cocoa are storing what we call reals in different ways, and I suspect that means any final rounding is going to have to be done in AS, or involve coercing from text in AS.

Well, maybe I’m just tired, but this worked somehow:

((theRoundedValueAsString as string) as real)

But will it work on different locales? That I am unsure… will have to be tried.

And I think before I tried to coerce straight to real, without coercing to string. That might have been the problem.

Crossing fingers…

Tx!

Browser: Safari 531.22.7
Operating System: Mac OS X (10.6)

So it means that the final routine would be like this:

on roundThisNumber_toThisDecimalPlaces_withThisRoundingMethod_(number_to_round, decimal_places, rounding_method)
		(*
		1 = NSNumberFormatterRoundCeiling = Round up to next larger number with the proper number of digits after the decimal separator.
		2 = NSNumberFormatterRoundFloor = Round down to next smaller number with the proper number of digits after the decimal separator.
		3 = NSNumberFormatterRoundDown = Round down to next smaller number with the proper number of digits after the decimal separator.
		4 = NSNumberFormatterRoundUp = Round the last digit, when followed by a 5, toward an even digit (.25 -> .2, .35 -> .4)
		5 = NSNumberFormatterRoundHalfEven = Round up to next larger number with the proper number of digits after the decimal separator.
		6 = NSNumberFormatterRoundHalfDown = Round down when a 5 follows putative last digit.
		7 = NSNumberFormatterRoundHalfUp = Round up when a 5 follows putative last digit.
		*)
		set roundingMethods to {¬
			current application's NSNumberFormatterRoundCeiling, ¬
			current application's NSNumberFormatterRoundFloor, ¬
			current application's NSNumberFormatterRoundDown, ¬
			current application's NSNumberFormatterRoundUp, ¬
			current application's NSNumberFormatterRoundHalfEven, ¬
			current application's NSNumberFormatterRoundHalfDown, ¬
			current application's NSNumberFormatterRoundHalfUp}
		
		set theRoundingFormat to "0.##" as string --default decimal places format
		if rounding_method < 1 and rounding_method > 7 then set rounding_method to 7 --make sure we have a valid default rounding method
		
		if (decimal_places as integer) = 0 then
			set theRoundingFormat to "0" as string
		else if (decimal_places as integer) > 0 then
			set theRoundingFormat to "0." as string
			repeat with myCount from 1 to (decimal_places as integer)
				set theRoundingFormat to (theRoundingFormat & "#") as string
			end repeat
		end if
		
		set number_formatter to current application's NSNumberFormatter's alloc()'s init()
		tell number_formatter
			setFormat_(theRoundingFormat)
			setRoundingMode_(item rounding_method of roundingMethods)
			set theRoundedValueAsString to stringFromNumber_(number_to_round)
		end tell
		return ((theRoundedValueAsString as string) as real) --This is where the magic happens
end roundThisNumber_toThisDecimalPlaces_withThisRoundingMethod_

… this one returns a real, not a string, so other math can be done on it.

Browser: Safari 531.22.7
Operating System: Mac OS X (10.6)