Number names: Difference between revisions

Content added Content deleted
No edit summary
(→‎{{header|AppleScript}}: Added long-scale options.)
Line 544: Line 544:
NSNumberFormatter supports several natural languages and by default uses the one set for the user on the host machine. However, its English is limited to US English, so there are no "and"s in the results.
NSNumberFormatter supports several natural languages and by default uses the one set for the user on the host machine. However, its English is limited to US English, so there are no "and"s in the results.


Vanilla AppleScript can be more flexible if you're prepared to write the code. The following script, like the ASObjC one above, returns short-scale number names (which are easier to code anyway) and includes "and"s by default. However an optional parameter <code>without ands</code> can be used in the call if you'd prefer not to have them. Alternatively, changing the <code>true</code> in the top line of the handler to <code>false</code> will ''omit'' "and"s by default and calls will have to include <code>with ands</code> to get them.
Vanilla AppleScript can be more flexible if you're prepared to write the code. The script below, like the ASObjC one above, returns short-scale number names, but includes "and"s by default. An optional parameter <code>without ands</code> can be added to the call if the "and"s are not wanted. Another optional parameter, <code>with longScale</code>, gets a British-English long-scale result, while a third, <code>with milliards</code>, gets a long-scale result with "milliard", "billiard", ''etc.'' between the "-illion"s instead of "thousand".


Both scripts can display strange results with numbers that are at the extreme limits of their floating-point resolution.
Both scripts can display strange results with numbers at the extreme limits of floating-point resolution.


<lang applescript>-- Parameters:
<lang applescript>-- Parameters:
-- n: AppleScript integer or real.
-- n: AppleScript integer or real.
-- longScale (optional): boolean. Whether to use long-scale -illions instead of short-scale. Default: false
-- milliards (optional): boolean. Whether to use long-scale -illiards instead of long-scale thousands.
-- ands (optional): boolean. Whether to include "and"s in the result. Default: true.
-- ands (optional): boolean. Whether to include "and"s in the result. Default: true.
on numberToEnglish from n given ands:usingAnd : true
on numberToEnglish from n given longScale:usingLongScale : false, milliards:usingMilliards : false, ands:usingAnd : true
-- If 'with milliards' is specified, make sure the differently coded 'with longScale' is disabled.
-- Script object containing the word lists and a recursive subhandler.
if (usingMilliards) then set (usingLongScale) to false
-- Script object containing data and two subhandlers.
script o
script o
property scale : 1000
property unitsAndTeens : {"one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", ¬
property unitsAndTeens : {"one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", ¬
"eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"}
"eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"}
property tens : {missing value, "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"}
property tens : {missing value, "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"}
property landmarks : {"thousand", "million", "billion", "trillion", "quadrillion", "quintillion", "sextillion"}
property landmarks : {"thousand", "million", "billion", "trillion", "quadrillion", "quintillion", "sextillion", "septillion"}
property illiardLandmarks : {"thousand", "million", "milliard", "billion", "billiard", "trillion", "trilliard", "quadrillion", ¬
"quadrilliard", "quintillion", "quintilliard", "sextillion", "sextilliard", "septillion", "septilliard"}
property collector : {} -- Words collected here.
property collector : {} -- Words collected here.
-- Recursive subhandler for the integer part of the number.
-- Deal with the integer part of the number.
on parseInt(n, landmarkNo)
on nameInteger(n, landmarkIndex)
-- Recursively work to the "front" of the integer "three digits" at a time.
-- Recursively work to the "front" of the number, three or six "digits" at a time depending on the scale.
if (n > 999) then parseInt(n div 1000, landmarkNo + 1)
if (n scale) then nameInteger(n div scale, landmarkIndex + 1)
-- Deal with each "three-digit" value on the way back.
-- Name each digit-group value on the way back.
set hundredsTensAndUnits to n mod 1000
set groupValue to n mod scale
-- Firstly the hundreds, if any. They'll only be single digits.
-- If a group value's over 999, its top three digits represent thousands in a long-scale naming. Deal with them first.
if (hundredsTensAndUnits > 99) then
if (groupValue > 999) then
set end of my collector to item (hundredsTensAndUnits div 100) of unitsAndTeens
nameGroup(groupValue div 1000, false, landmarkIndex)
set end of my collector to "thousand"
-- In this context, if the group's bottom three digits amount to zero, the appropriate "-illion", if any, must be added here.
set groupValue to groupValue mod 1000
if ((groupValue is 0) and (landmarkIndex > 0)) then set end of my collector to item landmarkIndex of my landmarks
end if
-- Deal with either a short-scale digit group or the bottom three digits of a long-scale one.
if (groupValue > 0) then
nameGroup(groupValue, true, landmarkIndex)
if (landmarkIndex > 0) then set end of my collector to item landmarkIndex of my landmarks
end if
end nameInteger
-- Deal with a value representing a group of up to three digits.
on nameGroup(groupValue, notThousands, landmarkIndex)
-- Firstly the hundreds, if any.
if (groupValue > 99) then
set end of my collector to item (groupValue div 100) of unitsAndTeens
set end of my collector to "hundred"
set end of my collector to "hundred"
end if
end if
-- Then the tens and units together, according to whether they require single words, hyphenated words or none.
-- Then the tens and units together, according to whether they require single words, hyphenated words or none.
set tensAndUnits to n mod 100
set tensAndUnits to groupValue mod 100
if (tensAndUnits > 0) then
if (tensAndUnits > 0) then
-- Insert the word "and" if enabled and appropriate.
-- Insert the word "and" if enabled and appropriate.
Line 579: Line 604:
((collector ends with "hundred") ¬
((collector ends with "hundred") ¬
or (collector ends with "thousand") ¬
or (collector ends with "thousand") ¬
or ((landmarkNo is 0) and (collector is not {})))) then ¬
or ((notThousands) and (landmarkIndex is 0) and (collector is not {})))) then ¬
set end of my collector to "and"
set end of my collector to "and"
if (tensAndUnits < 20) then
if (tensAndUnits < 20) then
Line 592: Line 617:
end if
end if
end if
end if
end nameGroup
-- Insert the "landmark" word for this point in the number, if applicable.
if ((hundredsTensAndUnits > 0) and (landmarkNo > 0)) then set end of my collector to item landmarkNo of my landmarks
end parseInt
end script
end script
-- Main handler code.
(* Main handler code. *)
-- Adjust for a negative if required.
-- Adjust for a negative if necessary.
if (n < 0) then
if (n < 0) then set {end of o's collector, n} to {"minus", -n}
set end of o's collector to "minus"
set n to -n
-- Deal with the integer part of the number.
end if
-- Deal with the integer part of the number first. Special-case zero, but otherwise parse.
if (n div 1 is 0) then
if (n div 1 is 0) then
set end of o's collector to "zero"
set end of o's collector to "zero"
else
else
tell o to parseInt(n div 1, 0)
if (usingLongScale) then
set o's scale to 1000000
set o's landmarks to rest of o's landmarks
else if (usingMilliards) then
set o's landmarks to o's illiardLandmarks
end if
tell o to nameInteger(n div 1, 0)
end if
end if
-- Deal with any fractional part, working forwards from the decimal point. (Vulnerable to floating-point inaccuracy at extreme lengths.)
-- Deal with any fractional part. (Vulnerable to floating-point inaccuracy with extreme values.)
if (n mod 1 > 0.0) then
if (n mod 1 > 0.0) then
set end of o's collector to "point"
set end of o's collector to "point"
Line 635: Line 663:
end numberToEnglish
end numberToEnglish


numberToEnglish from -3.6028797018963E+10
numberToEnglish from -3.60287970189634E+12
--> "minus thirty-six billion twenty-eight million seven hundred and ninety-seven thousand and eighteen point nine six three"
--> "minus three trillion six hundred and two billion eight hundred and seventy-nine million seven hundred and one thousand eight hundred and ninety-six point three four"
numberToEnglish from -3.6028797018963E+10 without ands
numberToEnglish from -3.60287970189634E+12 without ands
--> "minus thirty-six billion twenty-eight million seven hundred ninety-seven thousand eighteen point nine six three"</lang>
--> "minus three trillion six hundred two billion eight hundred seventy-nine million seven hundred one thousand eight hundred ninety-six point three four"
numberToEnglish from -3.60287970189634E+12 with longScale
--> "minus three billion six hundred and two thousand eight hundred and seventy-nine million seven hundred and one thousand eight hundred and ninety-six point three four"
numberToEnglish from -3.60287970189634E+12 with milliards
--> "minus three billion six hundred and two milliard eight hundred and seventy-nine million seven hundred and one thousand eight hundred and ninety-six point three four"</lang>


=={{header|Applesoft BASIC}}==
=={{header|Applesoft BASIC}}==