Help with sending a rounded number back to Quark

Hi,

The idea of my script is to increase prices in a Quark document by the requested percentage increase, I managed to get the script to work except for rounding the number to the required 2 decimal places, after some research I discovered the round truncate and number to string handlers which I have included in my script. Here is the script:


--Number to string handler
on number_to_string(this_number)
	set this_number to this_number as string
	if this_number contains "E+" then
		set x to the offset of "." in this_number
		set y to the offset of "+" in this_number
		set z to the offset of "E" in this_number
		set the decimal_adjust to characters (y - (length of this_number)) thru -1 of this_number as string as number
		if x is not 0 then
			set the first_part to characters 1 thru (x - 1) of this_number as string
		else
			set the first_part to ""
		end if
		set the second_part to characters (x + 1) thru (z - 1) of this_number as string
		set the converted_number to the first_part
		repeat with i from 1 to the decimal_adjust
			try
				set the converted_number to the converted_number & character i of the second_part
			on error
				set the converted_number to the converted_number & "0"
			end try
		end repeat
		return the converted_number
	else
		return this_number
	end if
end number_to_string

--Round truncate handler
on round_truncate(this_number, decimal_places)
	if decimal_places is 0 then
		set this_number to this_number + 0.5
		return number_to_text(this_number div 1)
	end if
	
	set the rounding_value to "5"
	repeat decimal_places times
		set the rounding_value to "0" & the rounding_value
	end repeat
	set the rounding_value to ("." & the rounding_value) as number
	
	set this_number to this_number + rounding_value
	
	set the mod_value to "1"
	repeat decimal_places - 1 times
		set the mod_value to "0" & the mod_value
	end repeat
	set the mod_value to ("." & the mod_value) as number
	
	set second_part to (this_number mod 1) div the mod_value
	if the length of (the second_part as text) is less than the decimal_places then
		repeat decimal_places - (the length of (the second_part as text)) times
			set second_part to ("0" & second_part) as string
		end repeat
	end if
	
	set first_part to this_number div 1
	set first_part to number_to_string(first_part)
	set this_number to (first_part & "." & second_part)
	
	return this_number
end round_truncate

--Request percentage increase, retrieve number from Quark text box and apply increase
property the_choice : 10
tell application "QuarkXPress"
	set thePercentage to (display dialog "What percentage increase do you wish to apply" buttons {"Cancel", "OK"} default button "OK" default answer the_choice)
	if button returned of thePercentage is "Cancel" then error "User canceled." number -128
	set the_choice to the text returned of the thePercentage
	set the_choice to (the_choice / 100 + 1)
	tell current box of document 1
		try
			set ToChange to last word
			set Changed to (ToChange * the_choice)
		end try
	end tell
end tell

--Round the number to 2 decimal places
round_truncate(Changed, 2)

--Return rounded number to Quark and update text box
tell application "QuarkXPress"
	tell current box of document 1
		set the last word to Changed
	end tell
end tell

When the script is run without attempting to return the number to Quark I get the correct number displayed in the results box of applescript editor rounded to 2 decimal places. As soon as I include the return number to Quark and update text box part of my script, the number displayed in the text box within quark has been calculated correctly but hasn’t been rounded to the 2 decimal places. Any help with this would be much appreciated.

Hi PaisleyBoy,

Did you know that there is a Standard Additions scripting additions command ‘round’? If not see Standard Additions’ dictionary.

I don’t know about Quark.

gl,
kel

Hi,

you’re mixing up text and number types.
For example the_choice is supposed to be an integer value


set the_choice to (the text returned of the thePercentage) as integer

and

set ToChange to last word as integer

or

set ToChange to last word as real

depending on an integer or floating point value is expected

You need to set word in the box to the result from the truncation process, like this:

set Changed to round_truncate(Changed, 2)

tell application "QuarkXPress"
	tell current box of document 1
		set the last word to Changed
	end tell
end tell

I assume the Quark stuff and the handlers themselves are OK.

Hi,

Thanks for all the help, Nigel’s suggestion has solved the issue, so thanks again.

:smiley:

Hello.

I made a new handler to round numbers, that for all I know, should be as fast as the one used, but slightly shorter.

Edit
Added consideration of zero decimals, and zero decimal places.

Edit++

Added a test for division by zero. And, discoverered that it rounds .5 to zero, and not 1. See below for “usual_rounding”, which supports the regular way of rounding numbers.

And corrected the coercion to happen after the test.

set mnum to 0
set rnum to bankers_rounding(mnum, 3)
to bankers_rounding(aNumber, decimalPlaces)
	set factor to (10 ^ decimalPlaces)
	set aNumber to round (aNumber * factor)
	if aNumber ≠ 0 then set aNumber to aNumber / factor
	set aNumber to aNumber as text
	-- fills out missing zeros first we need decimal separator
	if decimalPlaces > 0 then
		set dec_sep to text 2 of (1 / 2 as text)
		set numlen to length of aNumber
		set decpos to offset of dec_sep in aNumber
		
		if decpos = 0 then
			set aNumber to aNumber & dec_sep
			set numlen to numlen + 1
			set decpos to numlen
		end if
		repeat (decimalPlaces - (numlen - decpos)) times
			set aNumber to aNumber & "0"
		end repeat
	else
		set aNumber to aNumber as integer as text
	end if
	return aNumber
end bankers_rounding

Hello.

It is properly tested, I had to fix the fix for division by zero.

This one I believe rounds more in terms with the OP’s wishes, as it rounds .5 to 1, and not zero.

set mnum to 14.3445
set rnum to usual_rounding(mnum, 3)
-- http://macscripter.net/viewtopic.php?pid=165353#p165353
to usual_rounding(aNumber, decimalPlaces)
	set factor to (10 ^ decimalPlaces)
	set aNumber to round (aNumber * factor) rounding as taught in school
	if aNumber ≠ 0 then set aNumber to aNumber / factor
	set aNumber to aNumber as text
	-- fills out missing zeros first we need decimal separator
	if decimalPlaces > 0 then
		set dec_sep to text 2 of (1 / 2 as text)
		set numlen to length of aNumber
		set decpos to offset of dec_sep in aNumber
		
		if decpos = 0 then
			set aNumber to aNumber & dec_sep
			set numlen to numlen + 1
			set decpos to numlen
		end if
		repeat (decimalPlaces - (numlen - decpos)) times
			set aNumber to aNumber & "0"
		end repeat
	else
		set aNumber to aNumber as integer as text
	end if
	return aNumber
end usual_rounding

Hello.

I had made one more bug, when the number of decimal places was zero. Post #7 and #8 are fixed.

Below is a general handler, that takes AppleScript’s parameter for rounding as the third argument.

set num to rounding(0.5, 0, as taught in school)
-- http://macscripter.net/viewtopic.php?pid=165356#p165356
	to rounding(aNumber, decimalPlaces, round_method)
		-- round_method can be: (AppleScript Language Guide p. 149)
		-- up: same as ceiling 14.5 --> 15
		-- down: same as floor 14.6 --> 14
		-- toward zero: discards fractional parts.
		-- to nearest: (bankers rounding) 1.5 --> 2 0.5 --> 0
		-- (rounds towards nearest *even* integer.)
		-- as taught in school:  Rounds to nearest integer
		-- (0.5 is rounded upwards.)
		
		set factor to (10 ^ decimalPlaces)
		set aNumber to round (aNumber * factor) rounding round_method
		if aNumber ≠ 0 then set aNumber to aNumber / factor
		set aNumber to aNumber as text
		-- fills out missing zeros first we need decimal separator
		if decimalPlaces > 0 then
			set dec_sep to text 2 of (1 / 2 as text)
			set numlen to length of aNumber
			set decpos to offset of dec_sep in aNumber
			
			if decpos = 0 then
				set aNumber to aNumber & dec_sep
				set numlen to numlen + 1
				set decpos to numlen
			end if
			repeat (decimalPlaces - (numlen - decpos)) times
				set aNumber to aNumber & "0"
			end repeat
		else
			set aNumber to aNumber as integer as text
		end if
		return aNumber
	end rounding