0

I've been using a simple little script for rounding numbers to the hundredths decimal place, however I've noticed that when the number ends in zero, it rounds up to the next decimal place. I need to preserve this decimal place.

For example: 7.49908302 would be rounded to 7.5 instead of 7.50.

How can I keep the hundredths decimal with this subroutine? Should I try something Perl or Objective C, as I've been told Applescript isn't the best for this sort of thing.

Here's the call:

set finalAge514years to (roundThis(age514years, 2))

Here's my rounding subroutine:

on roundThis(n, numDecimals)
    set x to 10 ^ numDecimals
    (((n * x) + 0.5) div 1) / x
end roundThis
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
pianoman
  • 815
  • 2
  • 16
  • 36
  • 1
    There is a difference between the actual _value_ (`7.5`) and how it's displayed (`7.50`). Your rounding works fine, you just need to format the displayed value with two decimal places. I suggest you search Google for "applescript number format". – Jim Garrison Aug 06 '14 at 15:24

3 Answers3

2

The numbers 7.5 and 7.50 are exactly the same, so Applescript truncates any unnecessary information when displaying the number. What you're really looking for is how to format that information when it is displayed. For that, you need to turn the number into a string, specifying the amount of decimal places you want to see during the conversion.

This method of formatting a number is actually considered one of the Essential sub-routines.

round_truncate(7.49908302, 2)
--> "7.50"

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

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
Darrick Herwehe
  • 3,553
  • 1
  • 21
  • 30
1

You specifically asked for a Perl or Objective-C alternative to Applescript.

Therefore, here is a Perl solution:

use strict;
use warnings;

print round_this(7.49908302, 2), "\n";

sub round_this {
  my ($n, $decimals) = @_;
  sprintf '%.*f', $decimals, $n;
}

output

7.50
Miller
  • 34,962
  • 4
  • 39
  • 60
Borodin
  • 126,100
  • 9
  • 70
  • 144
0

Well AppleScript does many things for you. Because normally 1.5 is not the same as 0.75 * 2 (or at least not stable) in a boolean expression. To make real comparison easy for you the 1.50 (the result of 0.75 * 2) will be coerced into 1.5 for you. To make it work in AppleScript you need a string representation of the real number. However coercing a real into a string, AppleScript will take the system's localization into consideration. So the decimal mark and thousand separator can be different between machines depending on it's system preferences. The rounding is done by AppleScript when coercing a real to an integer. So something like this can work for you:

set n to 7.49958302
set i to round n rounding toward zero
set f to (n - i) * 100 as integer
set f to text 1 thru 2 of (f & "00" as string)
set r to (i as string) & "." & f

When you need this string back to a real again you can easily use the run script command. The run script command is like an eval. In AppleScript code the real numbers are not localized.

run script "7.50"
dj bazzie wazzie
  • 3,472
  • 18
  • 23