Numerical and alphabetical suffixes
You are encouraged to solve this task according to the task description, using any language you may know.
This task is about expressing numbers with an attached (abutted) suffix multiplier(s), the suffix(es) could be:
- an alphabetic (named) multiplier which could be abbreviated
- metric multiplier(s) which can be specified multiple times
- "binary" multiplier(s) which can be specified multiple times
- explanation marks (!) which indicate a factorial or multifactorial
The (decimal) numbers can be expressed generally as:
{±} {digits} {.} {digits} ────── or ────── {±} {digits} {.} {digits} {E or e} {±} {digits}
where:
- numbers won't have embedded blanks (contrary to the expaciated examples above where whitespace was used for readability)
- this task will only be dealing with decimal numbers, both in the mantissa and exponent
- ± indicates an optional plus or minus sign (+ or -)
- digits are the decimal digits (0 ──► 9)
- the digits can have comma(s) interjected to separate the periods (thousands) such as: 12,467,000
- . is the decimal point, sometimes also called a dot
- e or E denotes the use of decimal exponentiation (a number multiplied by raising ten to some power)
This isn't a pure or perfect definition of the way we express decimal numbers, but it should convey the intent for this task.
The use of the word periods (thousands) is not meant to confuse, that word (as used above) is what the comma separates;
the groups of decimal digits are called periods, and in almost all cases, are groups of three decimal digits.
If an e or E is specified, there must be a legal number expressed before it, and there must be a legal (exponent) expressed after it.
Also, there must be some digits expressed in all cases, not just a sign and/or decimal point.
Superfluous signs, decimal points, exponent numbers, and zeros need not be preserved.
I.E.: +7 007 7.00 7E-0 7E000 70e-1 could all be expressed as 7
All numbers to be "expanded" can be assumed to be valid and there won't be a requirement to verify their validity.
- Abbreviated alphabetic suffixes to be supported (where the capital letters signify the minimum abbreation that can be used)
PAIRs multiply the number by 2 (as in pairs of shoes or pants) SCOres multiply the number by 20 (as 3score would be 60) DOZens multiply the number by 12 GRoss multiply the number by 144 (twelve dozen) GREATGRoss multiply the number by 1,728 (a dozen gross) GOOGOLs multiply the number by 10^100 (ten raised to the 100&sup>th power)
Note that the plurals are supported, even though they're usually used when expressing exact numbers (She has 2 dozen eggs, and dozens of quavas)
- Metric suffixes to be supported (whether or not they're officially sanctioned)
K multiply the number by 10^3 kilo (1,000) M multiply the number by 10^6 mega (1,000,000) G multiply the number by 10^9 giga (1,000,000,000) T multiply the number by 10^12 tera (1,000,000,000,000) P multiply the number by 10^15 peta (1,000,000,000,000,000) E multiply the number by 10^18 exa (1,000,000,000,000,000,000) Z multiply the number by 10^21 zetta (1,000,000,000,000,000,000,000) Y multiply the number by 10^24 yotta (1,000,000,000,000,000,000,000,000) X multiply the number by 10^27 xenta (1,000,000,000,000,000,000,000,000,000) W multiply the number by 10^30 wekta (1,000,000,000,000,000,000,000,000,000,000) V multiply the number by 10^33 vendeka (1,000,000,000,000,000,000,000,000,000,000,000) U multiply the number by 10^36 udekta (1,000,000,000,000,000,000,000,000,000,000,000,000)
- Binary suffixes to be supported (whether or not they're officially sanctioned)
Ki multiply the number by 2^10 kibi (1,024) Mi multiply the number by 2^20 mebi (1,048,576) Gi multiply the number by 2^30 gibi (1,073,741,824) Ti multiply the number by 2^40 tebi (1,099,571,627,776) Pi multiply the number by 2^50 pebi (1,125,899,906,884,629) Ei multiply the number by 2^60 exbi (1,152,921,504,606,846,976) Zi multiply the number by 2^70 zeb1 (1,180,591,620,717,411,303,424) Yi multiply the number by 2^80 yobi (1,208,925,819,614,629,174,706,176) Xi multiply the number by 2^90 xebi (1,237,940,039,285,380,274,899,124,224) Wi multiply the number by 2^100 webi (1,267,650,600,228,229,401,496,703,205,376) Vi multiply the number by 2^110 vebi (1,298,074,214,633,706,907,132,624,082,305,024) Ui multiply the number by 2^120 uebi (1,329,227,995,784,915,872,903,807,060,280,344,576)
All of the metric and binary suffixes can be expressed in lowercase, uppercase, or mixed case.
All of the metric and binary suffixes can be stacked (expressed multiple times), and also be intermixed:
I.E.: 123k 123K 123GKi 12.3GiGG 12.3e-7T .78E100e
- Factorial suffixes to be supported
! compute the (regular) factorial product: 5! is 5 × 4 × 3 × 2 × 1 = 120 !! compute the double factorial product: 8! is 8 × 6 × 4 × 2 = 384 !!! compute the triple factorial product: 8! is 8 × 5 × 2 = 80 !!!! compute the quadruple factorial product: 8! is 8 × 4 = 32 !!!!! compute the quintuple factorial product: 8! is 8 × 3 = 24 ··· the number of factorial symbols that can be specified is to be unlimited (as per what can be entered/typed) ···
Factorial suffixes aren't, of course, the usual type of multipliers, but are used here in a similar vein.
Multifactorials aren't to be confused with super─factorials where (4!)! would be (24)!.
- Task
-
- Using the test cases (below), show the "expanded" numbers here, on this page.
- For each list, show the input on one line, and also show the output on one line.
- When showing the input line, keep the spaces (whitespace) and case (capitalizations) as is.
- For each result (list) displayed on one line, separate each number with two blanks.
- Add commas to the output numbers were appropriate.
- Test cases
2greatGRo 24Gros 288Doz 1,728pairs 172.8SCOre 1,567 +1.567k 0.1567e-2m 25.123kK 25.123m 2.5123e-00002G 25.123kiKI 25.123Mi 2.5123e-00002Gi +.25123E-7Ei -.25123e-34Vikki 2e-77gooGols 9! 9!! 9!!! 9!!!! 9!!!!! 9!!!!!! 9!!!!!!! 9!!!!!!!! 9!!!!!!!!!
where the last number for the factorials has nine factorial symbols (!) after the 9
- Related tasks
- Multifactorial (which has a clearer and more succinct definition of multifactorials.)
- Factorial
- Metrics
- Counting
- Word frequency
- Letter frequency
- Jewels and stones
- I before E except after C
- Bioinformatics/base count
- Count occurrences of a substring
- Count how many vowels and consonants occur in a string
- Remove/replace
- XXXX redacted
- Conjugate a Latin verb
- Remove vowels from a string
- String interpolation (included)
- Strip block comments
- Strip comments from a string
- Strip a set of characters from a string
- Strip whitespace from a string -- top and tail
- Strip control codes and extended characters from a string
- Anagrams/Derangements/shuffling
- Word wheel
- ABC problem
- Sattolo cycle
- Knuth shuffle
- Ordered words
- Superpermutation minimisation
- Textonyms (using a phone text pad)
- Anagrams
- Anagrams/Deranged anagrams
- Permutations/Derangements
- Find/Search/Determine
- ABC words
- Odd words
- Word ladder
- Semordnilap
- Word search
- Wordiff (game)
- String matching
- Tea cup rim text
- Alternade words
- Changeable words
- State name puzzle
- String comparison
- Unique characters
- Unique characters in each string
- Extract file extension
- Levenshtein distance
- Palindrome detection
- Common list elements
- Longest common suffix
- Longest common prefix
- Compare a list of strings
- Longest common substring
- Find common directory path
- Words from neighbour ones
- Change e letters to i in words
- Non-continuous subsequences
- Longest common subsequence
- Longest palindromic substrings
- Longest increasing subsequence
- Words containing "the" substring
- Sum of the digits of n is substring of n
- Determine if a string is numeric
- Determine if a string is collapsible
- Determine if a string is squeezable
- Determine if a string has all unique characters
- Determine if a string has all the same characters
- Longest substrings without repeating characters
- Find words which contains all the vowels
- Find words which contain the most consonants
- Find words which contains more than 3 vowels
- Find words whose first and last three letters are equal
- Find words with alternating vowels and consonants
- Formatting
- Substring
- Rep-string
- Word wrap
- String case
- Align columns
- Literals/String
- Repeat a string
- Brace expansion
- Brace expansion using ranges
- Reverse a string
- Phrase reversals
- Comma quibbling
- Special characters
- String concatenation
- Substring/Top and tail
- Commatizing numbers
- Reverse words in a string
- Suffixation of decimal numbers
- Long literals, with continuations
- Numerical and alphabetical suffixes
- Abbreviations, easy
- Abbreviations, simple
- Abbreviations, automatic
- Song lyrics/poems/Mad Libs/phrases
- Mad Libs
- Magic 8-ball
- 99 bottles of beer
- The Name Game (a song)
- The Old lady swallowed a fly
- The Twelve Days of Christmas
- Tokenize
- Text between
- Tokenize a string
- Word break problem
- Tokenize a string with escaping
- Split a character string based on change of character
- Sequences
Factor
Functional
USING: combinators combinators.short-circuit formatting fry
grouping grouping.extras kernel literals math math.functions
math.parser math.ranges qw regexp sequences sequences.deep
sequences.extras sets splitting unicode ;
IN: rosetta-code.numerical-suffixes
CONSTANT: test-cases {
qw{ 2greatGRo 24Gros 288Doz 1,728pairs 172.8SCOre }
qw{ 1,567 +1.567k 0.1567e-2m }
qw{ 25.123kK 25.123m 2.5123e-00002G }
qw{ 25.123kiKI 25.123Mi 2.5123e-00002Gi +.25123E-7Ei }
qw{ -.25123e-34Vikki 2e-77gooGols }
qw{
9! 9!! 9!!! 9!!!! 9!!!!! 9!!!!!! 9!!!!!!! 9!!!!!!!!
9!!!!!!!!!
}
}
CONSTANT: alpha {
{ "PAIRs" 2 } { "DOZens" 12 } { "SCOres" 20 }
{ "GRoss" 144 } { "GREATGRoss" 1,728 }
${ "GOOGOLs" 10 100 ^ }
}
CONSTANT: metric qw{ K M G T P E Z Y X W V U }
! Multifactorial
: m! ( n degree -- m ) neg 1 swap <range> product ;
! Separate a number from its suffix(es).
! e.g. "+1.567k" -> 1.567 "k"
: num/suffix ( str -- n suffix(es) )
dup <head-clumps> <reversed> { } like "" map-like
[ string>number ] map [ ] find [ tail* ] dip swap ;
! Checks whether str1 is an abbreviation of str2.
! e.g. "greatGRo" "GREATGRoss" -> t
: abbrev? ( str1 str2 -- ? )
{
[ [ >upper ] [ [ LETTER? ] take-while head? ] bi* ]
[ [ length ] bi@ <= ]
} 2&& ;
! Convert an alpha suffix to its multiplication function.
! e.g. "Doz" -> [ 12 * ]
: alpha>quot ( str -- quot )
[ alpha ] dip '[ first _ swap abbrev? ] find nip second
[ * ] curry ;
! Split a suffix composed of metric and binary suffixes into its
! constituent parts. e.g. "Vikki" -> { "Vi" "k" "ki" }
: split-compound ( str -- seq )
R/ (.i|.)/i all-matching-subseqs ;
! Convert a metric or binary suffix to its multiplication
! function. e.g. "k" -> [ 10 3 ^ * ]
: suffix>quot ( str -- quot )
dup [ [ 0 1 ] dip subseq >upper metric index 1 + ] dip
length 1 = [ 3 * '[ 10 _ ^ * ] ] [ 10 * '[ 2 _ ^ * ] ] if ;
! Apply suffix>quot to each member of a sequence.
! e.g. { "Vi" "k" "ki" } ->
! [ [ 2 110 ^ * ] [ 10 3 ^ * ] [ 2 10 ^ * ] ]
: map-suffix ( seq -- seq' ) [ suffix>quot ] [ ] map-as ;
! Tests whether a string is composed of metric and/or binary
! suffixes. e.g. "Vikki" -> t
: compound? ( str -- ? )
>upper metric concat "I" append without empty? ;
! Convert a float to an integer if it is numerically equivalent
! to an integer. e.g. 1.0 -> 1, 1.23 -> 1.23
: ?f>i ( x -- y/n )
dup >integer 2dup [ number= ] 2dip swap ? ;
! Convert a suffix string to a function that performs the
! calculations required by the suffix.
! e.g. "!!!" -> [ 3 m! ], "kiKI" -> [ 2 10 ^ * 2 10 ^ * ]
: parse-suffix ( str -- quot )
{
{ [ dup empty? ] [ drop [ ] ] }
{ [ dup first CHAR: ! = ] [ length [ m! ] curry ] }
{ [ dup compound? ] [ split-compound map-suffix ] }
[ alpha>quot ]
} cond flatten ;
GENERIC: commas ( n -- str )
! Add commas to an integer in triplets.
! e.g. 1567 -> "1,567"
M: integer commas number>string <reversed> 3 group
[ "," append ] map concat reverse rest ;
! Add commas to a float in triplets.
! e.g. 1567.12345 -> "1,567.12345"
M: float commas number>string "." split first2
[ string>number commas ] dip "." glue ;
! Parse any number with any numerical or alphabetical suffix.
! e.g. "288Doz" -> "3,456", "9!!" -> "945"
: parse-alpha ( str -- str' )
num/suffix parse-suffix curry call( -- x ) ?f>i commas ;
: main ( -- )
test-cases [
dup [ parse-alpha ] map
"Numbers: %[%s, %]\n Result: %[%s, %]\n\n" printf
] each ;
MAIN: main
- Output:
Numbers: { 2greatGRo, 24Gros, 288Doz, 1,728pairs, 172.8SCOre } Result: { 3,456, 3,456, 3,456, 3,456, 3,456 } Numbers: { 1,567, +1.567k, 0.1567e-2m } Result: { 1,567, 1,567, 1,567 } Numbers: { 25.123kK, 25.123m, 2.5123e-00002G } Result: { 25,123,000, 25,123,000, 25,123,000 } Numbers: { 25.123kiKI, 25.123Mi, 2.5123e-00002Gi, +.25123E-7Ei } Result: { 26,343,374.848, 26,343,374.848, 26,975,615.844352, 28,964,846,960.23782 } Numbers: { -.25123e-34Vikki, 2e-77gooGols } Result: { -33,394.19493810444, 199,999,999,999,999,983,222,784 } Numbers: { 9!, 9!!, 9!!!, 9!!!!, 9!!!!!, 9!!!!!!, 9!!!!!!!, 9!!!!!!!!, 9!!!!!!!!! } Result: { 362,880, 945, 162, 45, 36, 27, 18, 9, 9 }
EBNF
This solution uses Factor's extended Backus-Naur form (EBNF) language to define a grammar for parsing numerical/alphabetical suffix numbers. The goal was to describe as much of the suffix-number as possible in a declarative manner, minimizing the use of actions (Factor code that is run on a rule before being added to the abstract syntax tree) and helper functions. The biggest departure from this goal was to parse the metric/binary suffixes based on their index in a collection, as this method is less verbose than defining a rule for each suffix.
USING: formatting fry grouping kernel literals math
math.functions math.parser math.ranges multiline peg.ebnf
quotations qw sequences sequences.deep splitting strings unicode ;
IN: rosetta-code.numerical-suffixes.ebnf
CONSTANT: test-cases {
qw{ 2greatGRo 24Gros 288Doz 1,728pairs 172.8SCOre }
qw{ 1,567 +1.567k 0.1567e-2m }
qw{ 25.123kK 25.123m 2.5123e-00002G }
qw{ 25.123kiKI 25.123Mi 2.5123e-00002Gi +.25123E-7Ei }
qw{ -.25123e-34Vikki 2e-77gooGols }
qw{
9! 9!! 9!!! 9!!!! 9!!!!! 9!!!!!! 9!!!!!!! 9!!!!!!!!
9!!!!!!!!!
}
}
CONSTANT: metric qw{ K M G T P E Z Y X W V U }
: suffix>quot ( str -- quot )
dup [ [ 0 1 ] dip subseq >upper metric index 1 + ] dip
length 1 = [ 3 * '[ 10 _ ^ * ] ] [ 10 * '[ 2 _ ^ * ] ] if ;
: ?f>i ( x -- y/n ) dup >integer 2dup [ number= ] 2dip swap ? ;
GENERIC: commas ( n -- str )
M: integer commas number>string <reversed> 3 group
[ "," append ] map concat reverse rest ;
M: float commas number>string "." split first2
[ string>number commas ] dip "." glue ;
EBNF: suffix-num [=[
sign = [+-]
digit = [0-9]
triplet = digit digit digit
commas = (triplet | digit digit | digit) ([,] triplet)+
integer = sign? (commas | digit+)
exp = [Ee] sign? digit+
bfloat = (integer | sign)? [.] digit+ exp?
float = (bfloat | integer exp)
number = (float | integer) => [[ flatten "" like string>number ]]
pairs = [Pp] [Aa] [Ii] [Rr] [s]? => [[ [ 2 * ] ]]
dozens = [Dd] [Oo] [Zz] [e]? [n]? [s]? => [[ [ 12 * ] ]]
scores = [Ss] [Cc] [Oo] [r]? [e]? [s]? => [[ [ 20 * ] ]]
gross = [Gg] [Rr] [o]? [s]? [s]? => [[ [ 144 * ] ]]
gg = [Gg] [Rr] [Ee] [Aa] [Tt] gross => [[ [ 1728 * ] ]]
googols = [Gg] [Oo] [Oo] [Gg] [Oo] [Ll] [s]? => [[ [ $[ 10 100 ^ ] * ] ]]
alpha = (pairs | dozens | scores | gg | gross | googols)
numeric = ([KkMmGgPpEeT-Zt-z] [Ii]?) => [[ flatten "" like suffix>quot ]]
ncompnd = numeric+
fact = [!]+ => [[ length [ neg 1 swap <range> product ] curry ]]
suffix = (alpha | ncompnd | fact)
s-num = number suffix? !(.) =>
[[ >quotation flatten call( -- x ) ?f>i commas ]]
]=]
: num-alpha-suffix-demo ( -- )
test-cases [
dup [ suffix-num ] map
"Numbers: %[%s, %]\n Result: %[%s, %]\n\n" printf
] each ;
MAIN: num-alpha-suffix-demo
- Output:
Numbers: { 2greatGRo, 24Gros, 288Doz, 1,728pairs, 172.8SCOre } Result: { 3,456, 3,456, 3,456, 3,456, 3,456 } Numbers: { 1,567, +1.567k, 0.1567e-2m } Result: { 1,567, 1,567, 1,567 } Numbers: { 25.123kK, 25.123m, 2.5123e-00002G } Result: { 25,123,000, 25,123,000, 25,123,000 } Numbers: { 25.123kiKI, 25.123Mi, 2.5123e-00002Gi, +.25123E-7Ei } Result: { 26,343,374.848, 26,343,374.848, 26,975,615.844352, 28,964,846,960.23782 } Numbers: { -.25123e-34Vikki, 2e-77gooGols } Result: { -33,394.19493810444, 199,999,999,999,999,983,222,784 } Numbers: { 9!, 9!!, 9!!!, 9!!!!, 9!!!!!, 9!!!!!!, 9!!!!!!!, 9!!!!!!!!, 9!!!!!!!!! } Result: { 362,880, 945, 162, 45, 36, 27, 18, 9, 9 }
FreeBASIC
Type minmult
min As Integer
mult As Double
End Type
Type suffix_entry
key As String
value As minmult
End Type
Type metric_entry
key As String
value As Double
End Type
Dim Shared As suffix_entry abbrevs(5)
Dim Shared As metric_entry metric(11)
Dim Shared As metric_entry binary_metric(11)
Sub initialize_data()
' Initialize abbrevs
abbrevs(0).key = "PAIRs" : abbrevs(0).value.min = 4 : abbrevs(0).value.mult = 2
abbrevs(1).key = "SCOres" : abbrevs(1).value.min = 3 : abbrevs(1).value.mult = 20
abbrevs(2).key = "DOZens" : abbrevs(2).value.min = 3 : abbrevs(2).value.mult = 12
abbrevs(3).key = "GRoss" : abbrevs(3).value.min = 2 : abbrevs(3).value.mult = 144
abbrevs(4).key = "GREATGRoss" : abbrevs(4).value.min = 7 : abbrevs(4).value.mult = 1728
abbrevs(5).key = "GOOGOLs" : abbrevs(5).value.min = 6 : abbrevs(5).value.mult = 1e100
' Initialize metric
metric(0).key = "K" : metric(0).value = 1e3
metric(1).key = "M" : metric(1).value = 1e6
metric(2).key = "G" : metric(2).value = 1e9
metric(3).key = "T" : metric(3).value = 1e12
metric(4).key = "P" : metric(4).value = 1e15
metric(5).key = "E" : metric(5).value = 1e18
metric(6).key = "Z" : metric(6).value = 1e21
metric(7).key = "Y" : metric(7).value = 1e24
metric(8).key = "X" : metric(8).value = 1e27
metric(9).key = "W" : metric(9).value = 1e30
metric(10).key = "V" : metric(10).value = 1e33
metric(11).key = "U" : metric(11).value = 1e36
' Initialize binary_metric
binary_metric(0).key = "Ki" : binary_metric(0).value = 2^10
binary_metric(1).key = "Mi" : binary_metric(1).value = 2^20
binary_metric(2).key = "Gi" : binary_metric(2).value = 2^30
binary_metric(3).key = "Ti" : binary_metric(3).value = 2^40
binary_metric(4).key = "Pi" : binary_metric(4).value = 2^50
binary_metric(5).key = "Ei" : binary_metric(5).value = 2^60
binary_metric(6).key = "Zi" : binary_metric(6).value = 2^70
binary_metric(7).key = "Yi" : binary_metric(7).value = 2^80
binary_metric(8).key = "Xi" : binary_metric(8).value = 2^90
binary_metric(9).key = "Wi" : binary_metric(9).value = 2^100
binary_metric(10).key = "Vi" : binary_metric(10).value = 2^110
binary_metric(11).key = "Ui" : binary_metric(11).value = 2^120
End Sub
Function fact(num As String, d As Integer) As Longint
Dim As Longint prod = 1
Dim As Integer i, n = Val(num)
For i = n To 1 Step -d
prod *= i
Next
Return prod
End Function
Function removeCommas(s As String) As String
Dim As String result = ""
For i As Integer = 1 To Len(s)
If Mid(s, i, 1) <> "," Then result &= Mid(s, i, 1)
Next
Return result
End Function
Function parse(number As String) As Double
Dim As Integer i, j, k
Dim As String num, suf
Dim As Double result = 0
' find index of last digit
For i = Len(number) - 1 To 0 Step -1
If Mid(number, i + 1, 1) >= "0" And Mid(number, i + 1, 1) <= "9" Then Exit For
Next
num = Left(number, i + 1)
num = Trim(removeCommas(num)) ' get rid of any commas
suf = Ucase(Mid(number, i + 2))
If suf = "" Then Return Val(num)
If Left(suf, 1) = "!" Then Return fact(num, Len(suf))
For i = 0 To Ubound(abbrevs)
Dim As String k = Ucase(abbrevs(i).key)
If Left(k, Len(suf)) = suf And Len(suf) >= abbrevs(i).value.min Then
Return Val(num) * abbrevs(i).value.mult
End If
Next
result = Val(num)
For i = 1 To Len(suf)
For j = 0 To Ubound(metric)
If Mid(suf, i, 1) = metric(j).key Then
If i < Len(suf) And Mid(suf, i + 1, 1) = "I" Then
For k = 0 To Ubound(binary_metric)
If binary_metric(k).key = metric(j).key & "i" Then
result *= binary_metric(k).value
i += 1
Exit For
End If
Next
Else
result *= metric(j).value
End If
End If
Next
Next
Return result
End Function
Function commatize(s As String) As String
If Len(s) = 0 Then Return ""
Dim As Boolean neg = (Left(s, 1) = "-")
If neg Then s = Mid(s, 2)
Dim As String fracci = ""
Dim As Integer ix, le, i
ix = Instr(s, ".")
If ix > 0 Then
fracci = Mid(s, ix)
s = Left(s, ix - 1)
End If
le = Len(s)
For i = le - 3 To 1 Step -3
s = Left(s, i) & "," & Mid(s, i + 1)
Next
Return Iif(neg, "-", "") & s & fracci
End Function
Sub process(numbers() As String)
Dim As Integer i
Print "Numbers = ";
For i = 0 To Ubound(numbers)
Print numbers(i); " ";
Next
Print !"\nResults = ";
For i = 0 To Ubound(numbers)
Dim As Double res = parse(numbers(i))
Print commatize(Str(res)); " ";
Next
Print Chr(10)
End Sub
' Main program
initialize_data()
Dim As String numbers()
Redim numbers(4)
numbers(0) = "2greatGRo"
numbers(1) = "24Gros"
numbers(2) = "288Doz"
numbers(3) = "1,728pairs"
numbers(4) = "172.8SCOre"
process(numbers())
Redim numbers(2)
numbers(0) = "1,567"
numbers(1) = "+1.567k"
numbers(2) = "0.1567e-2m"
process(numbers())
Redim numbers(2)
numbers(0) = "25.123kK"
numbers(1) = "25.123m"
numbers(2) = "2.5123e-00002G"
process(numbers())
Redim numbers(3)
numbers(0) = "25.123kiKI"
numbers(1) = "25.123Mi"
numbers(2) = "2.5123e-00002Gi"
numbers(3) = "+.25123E-7Ei"
process(numbers())
Redim numbers(1)
numbers(0) = "-.25123e-34Vikki"
numbers(1) = "2e-77gooGols"
process(numbers())
Redim numbers(8)
numbers(0) = "9!"
numbers(1) = "9!!"
numbers(2) = "9!!!"
numbers(3) = "9!!!!"
numbers(4) = "9!!!!!"
numbers(5) = "9!!!!!!"
numbers(6) = "9!!!!!!!"
numbers(7) = "9!!!!!!!!"
numbers(8) = "9!!!!!!!!!"
process(numbers())
Sleep
- Output:
Numbers = 2greatGRo 24Gros 288Doz 1,728pairs 172.8SCOre Results = 3,456 3,456 3,456 3,456 3,456 Numbers = 1,567 +1.567k 0.1567e-2m Results = 1,567 1,567 1,567 Numbers = 25.123kK 25.123m 2.5123e-00002G Results = 25,123,000 25,123,000 25,123,000 Numbers = 25.123kiKI 25.123Mi 2.5123e-00002Gi +.25123E-7Ei Results = 26,343,374.848 26,343,374.848 26,975,615.844352 28,964,846,960.23782 Numbers = -.25123e-34Vikki 2e-77gooGols Results = -33,394.19493810444 2e+,023 Numbers = 9! 9!! 9!!! 9!!!! 9!!!!! 9!!!!!! 9!!!!!!! 9!!!!!!!! 9!!!!!!!!! Results = 362,880 945 162 45 36 27 18 9 9
Go
package main
import (
"fmt"
"math"
"math/big"
"strconv"
"strings"
)
type minmult struct {
min int
mult float64
}
var abbrevs = map[string]minmult{
"PAIRs": {4, 2}, "SCOres": {3, 20}, "DOZens": {3, 12},
"GRoss": {2, 144}, "GREATGRoss": {7, 1728}, "GOOGOLs": {6, 1e100},
}
var metric = map[string]float64{
"K": 1e3, "M": 1e6, "G": 1e9, "T": 1e12, "P": 1e15, "E": 1e18,
"Z": 1e21, "Y": 1e24, "X": 1e27, "W": 1e30, "V": 1e33, "U": 1e36,
}
var binary = map[string]float64{
"Ki": b(10), "Mi": b(20), "Gi": b(30), "Ti": b(40), "Pi": b(50), "Ei": b(60),
"Zi": b(70), "Yi": b(80), "Xi": b(90), "Wi": b(100), "Vi": b(110), "Ui": b(120),
}
func b(e float64) float64 {
return math.Pow(2, e)
}
func googol() *big.Float {
g1 := new(big.Float).SetPrec(500)
g1.SetInt64(10000000000)
g := new(big.Float)
g.Set(g1)
for i := 2; i <= 10; i++ {
g.Mul(g, g1)
}
return g
}
func fact(num string, d int) int {
prod := 1
n, _ := strconv.Atoi(num)
for i := n; i > 0; i -= d {
prod *= i
}
return prod
}
func parse(number string) *big.Float {
bf := new(big.Float).SetPrec(500)
t1 := new(big.Float).SetPrec(500)
t2 := new(big.Float).SetPrec(500)
// find index of last digit
var i int
for i = len(number) - 1; i >= 0; i-- {
if '0' <= number[i] && number[i] <= '9' {
break
}
}
num := number[:i+1]
num = strings.Replace(num, ",", "", -1) // get rid of any commas
suf := strings.ToUpper(number[i+1:])
if suf == "" {
bf.SetString(num)
return bf
}
if suf[0] == '!' {
prod := fact(num, len(suf))
bf.SetInt64(int64(prod))
return bf
}
for k, v := range abbrevs {
kk := strings.ToUpper(k)
if strings.HasPrefix(kk, suf) && len(suf) >= v.min {
t1.SetString(num)
if k != "GOOGOLs" {
t2.SetFloat64(v.mult)
} else {
t2 = googol() // for greater accuracy
}
bf.Mul(t1, t2)
return bf
}
}
bf.SetString(num)
for k, v := range metric {
for j := 0; j < len(suf); j++ {
if k == suf[j:j+1] {
if j < len(suf)-1 && suf[j+1] == 'I' {
t1.SetFloat64(binary[k+"i"])
bf.Mul(bf, t1)
j++
} else {
t1.SetFloat64(v)
bf.Mul(bf, t1)
}
}
}
}
return bf
}
func commatize(s string) string {
if len(s) == 0 {
return ""
}
neg := s[0] == '-'
if neg {
s = s[1:]
}
frac := ""
if ix := strings.Index(s, "."); ix >= 0 {
frac = s[ix:]
s = s[:ix]
}
le := len(s)
for i := le - 3; i >= 1; i -= 3 {
s = s[0:i] + "," + s[i:]
}
if !neg {
return s + frac
}
return "-" + s + frac
}
func process(numbers []string) {
fmt.Print("numbers = ")
for _, number := range numbers {
fmt.Printf("%s ", number)
}
fmt.Print("\nresults = ")
for _, number := range numbers {
res := parse(number)
t := res.Text('g', 50)
fmt.Printf("%s ", commatize(t))
}
fmt.Println("\n")
}
func main() {
numbers := []string{"2greatGRo", "24Gros", "288Doz", "1,728pairs", "172.8SCOre"}
process(numbers)
numbers = []string{"1,567", "+1.567k", "0.1567e-2m"}
process(numbers)
numbers = []string{"25.123kK", "25.123m", "2.5123e-00002G"}
process(numbers)
numbers = []string{"25.123kiKI", "25.123Mi", "2.5123e-00002Gi", "+.25123E-7Ei"}
process(numbers)
numbers = []string{"-.25123e-34Vikki", "2e-77gooGols"}
process(numbers)
numbers = []string{"9!", "9!!", "9!!!", "9!!!!", "9!!!!!", "9!!!!!!",
"9!!!!!!!", "9!!!!!!!!", "9!!!!!!!!!"}
process(numbers)
}
- Output:
numbers = 2greatGRo 24Gros 288Doz 1,728pairs 172.8SCOre results = 3,456 3,456 3,456 3,456 3,456 numbers = 1,567 +1.567k 0.1567e-2m results = 1,567 1,567 1,567 numbers = 25.123kK 25.123m 2.5123e-00002G results = 25,123,000 25,123,000 25,123,000 numbers = 25.123kiKI 25.123Mi 2.5123e-00002Gi +.25123E-7Ei results = 26,343,374.848 26,343,374.848 26,975,615.844352 28,964,846,960.237816578048 numbers = -.25123e-34Vikki 2e-77gooGols results = -33,394.194938104441474962344775423096782848 200,000,000,000,000,000,000,000 numbers = 9! 9!! 9!!! 9!!!! 9!!!!! 9!!!!!! 9!!!!!!! 9!!!!!!!! 9!!!!!!!!! results = 362,880 945 162 45 36 27 18 9 9
Julia
using Formatting
partialsuffixes = Dict("PAIR" => "PAIRS", "SCO" => "SCORES", "DOZ" => "DOZENS",
"GR" => "GROSS", "GREATGR" => "GREATGROSS", "GOOGOL" => "GOOGOLS")
partials = sort(collect(keys(partialsuffixes)), lt=(a,b)->length(a)<length(b), rev=true)
multicharsuffixes = Dict("PAIRS" => 2, "SCORES" => 20, "DOZENS" => 12, "GROSS" => 144,
"GREATGROSS" => 1728, "GOOGOLS" => BigInt(10)^100)
twocharsuffixes = Dict(
"KI" => BigInt(2)^10, "MI" => BigInt(2)^20, "GI" => BigInt(2)^30, "TI" => BigInt(2)^40,
"PI" => BigInt(2)^50, "EI" => BigInt(2)^60, "ZI" => BigInt(2)^70, "YI" => BigInt(2)^80,
"XI" => BigInt(2)^90, "WI" => BigInt(2)^100, "VI" => BigInt(2)^110, "UI" => BigInt(2)^120)
twosuff = collect(keys(twocharsuffixes))
onecharsuffixes = Dict("K" => 10^3, "M" => 10^6, "G" => 10^9, "T" => 10^12, "P" => 10^15,
"E" => 10^18, "Z" => 10^21, "Y" => BigInt(10)^24,
"X" => BigInt(10)^27, "W" => BigInt(10)^30,
"V" => BigInt(10)^33, "U" => BigInt(10)^36)
onesuff = collect(keys(onecharsuffixes))
function firstsuffix(s, x)
str = uppercase(s)
if str[1] == '!'
lastbang = something(findfirst(x -> x != '!', str), length(str))
return prod(x:-lastbang:1) / x, lastbang
end
for pstr in partials
if match(Regex("^" * pstr), str) != nothing
fullsuffix = partialsuffixes[pstr]
n = length(pstr)
while n < length(fullsuffix) && n < length(str) && fullsuffix[n+1] == str[n+1]
n += 1
end
return BigInt(multicharsuffixes[fullsuffix]), n
end
end
for pstr in twosuff
if match(Regex("^" * pstr), str) != nothing
return BigInt(twocharsuffixes[pstr]), 2
end
end
for pstr in onesuff
if match(Regex("^" * pstr), str) != nothing
return BigInt(onecharsuffixes[pstr]), 1
end
end
return 1, length(s)
end
function parsesuffix(s, x)
str = s
mult = BigInt(1)
n = 1
while n <= length(str)
multiplier, n = firstsuffix(str, x)
mult *= multiplier
str = str[n+1:end]
end
mult
end
function suffixednumber(s)
if (endnum = findlast(isdigit, s)) == nothing
return NaN
end
x = BigFloat(replace(s[1:endnum], "," => ""))
return x * (endnum < length(s) ? parsesuffix(s[endnum + 1:end], x) : 1)
end
const testcases =
["2greatGRo 24Gros 288Doz 1,728pairs 172.8SCOre",
"1,567 +1.567k 0.1567e-2m",
"25.123kK 25.123m 2.5123e-00002G",
"25.123kiKI 25.123Mi 2.5123e-00002Gi +.25123E-7Ei",
"-.25123e-34Vikki 2e-77gooGols",
"9! 9!! 9!!! 9!!!! 9!!!!! 9!!!!!! 9!!!!!!! 9!!!!!!!! 9!!!!!!!!!"]
function testsuffixes()
for line in testcases
cases = split(line)
println("Testing: ", string.(cases))
println("Results: ", join(map(x -> format(suffixednumber(x), commas=true), cases), " "), "\n")
end
end
testsuffixes()
- Output:
Testing: ["2greatGRo", "24Gros", "288Doz", "1,728pairs", "172.8SCOre"] Results: 3,456 3,456 3,456 3,456 3,456 Testing: ["1,567", "+1.567k", "0.1567e-2m"] Results: 1,567 1,567 1,567 Testing: ["25.123kK", "25.123m", "2.5123e-00002G"] Results: 25,123,000 25,123,000 25,123,000 Testing: ["25.123kiKI", "25.123Mi", "2.5123e-00002Gi", "+.25123E-7Ei"] Results: 26,343,374.848 26,343,374.848 26,975,615.844352 28,964,846,960.237817 Testing: ["-.25123e-34Vikki", "2e-77gooGols"] Results: -33,394.194938 200,000,000,000,000,000,000,000 Testing: ["9!", "9!!", "9!!!", "9!!!!", "9!!!!!", "9!!!!!!", "9!!!!!!!", "9!!!!!!!!", "9!!!!!!!!!"] Results: 362,880 945 162 45 36 27 18 9 9
Nim
import re, strutils, parseutils, tables, math
const input = """
2greatGRo 24Gros 288Doz 1,728pairs 172.8SCOre
1,567 +1.567k 0.1567e-2m
25.123kK 25.123m 2.5123e-00002G
25.123kiKI 25.123Mi 2.5123e-00002Gi +.25123E-7Ei
-.25123e-34Vikki 2e-77gooGols
9! 9!! 9!!! 9!!!! 9!!!!! 9!!!!!! 9!!!!!!! 9!!!!!!!! 9!!!!!!!!!
"""
let
abbrAlpha = re(r"(PAIR)(s)?$|(SCO)(r|re|res)?$|(DOZ)(e|en|ens)?$|(GR)(o|os|oss)?$|(GREATGR)(o|os|oss)?$|(GOOGOL)(s)?$",
flags = {reIgnoreCase})
metricBinary = re(r"[KMGTPEZYXWVU]i?", flags = {reIgnoreCase})
factorial = re"!+$"
const
alphaValues = [2e0, 20e0, 12e0, 144e0, 1728e0, 1e100]
metricBinaryValueTab = {"K": 10.0^3, "KI": 2.0^10, "M": 10.0^6, "MI": 2.0^20,
"G": 10.0^9, "GI": 2.0^30, "T": 10.0^12, "TI": 2.0^40, "P": 10.0^15,
"PI": 2.0^50, "E": 10.0^18, "EI": 2.0^60, "Z": 10.0^21, "ZI": 2.0^70,
"Y": 10.0^24, "YI": 2.0^80, "X": 10.0^27, "XI": 2.0^90, "W": 10.0^30,
"WI": 2.0^100, "V": 10.0^33, "VI": 2.0^110, "U": 10.0^36,
"UI": 2.0^120}.toTable
var
matches: array[12, string]
res, fac: float
suffix: string
proc sepFloat(f: float): string =
var
s = $f
i, num: int
num = parseInt(s, i)
if num == 0:
return s
else:
return insertSep($i, ',', 3)&s[num..^1]
for line in input.splitLines():
if not isEmptyOrWhiteSpace(line):
echo("Input:\n", line, "\nOutput:")
var output = " "
for raw_number in line.replace(",", "").splitWhiteSpace():
suffix = raw_number[parseutils.parseFloat(raw_number, res)..^1].toUpper()
if suffix.match(abbrAlpha, matches):
for i, v in matches.mpairs():
if i mod 2 == 0 and not v.isEmptyOrWhiteSpace():
res*=alphaValues[i div 2]
v = ""
break
elif suffix.match(factorial):
fac = abs(res)-toFloat(len(suffix))
while fac > 0:
res*=fac
fac-=toFloat(len(suffix))
elif suffix.match(metricBinary):
for m in suffix.findAll(metricBinary):
res*=metricBinaryValueTab[m]
output &= sepFloat(res)&" "
echo(output)
- Output:
Input:
2greatGRo 24Gros 288Doz 1,728pairs 172.8SCOreOutput:
3,456.0 3,456.0 3,456.0 3,456.0 3,456.0Input:
1,567 +1.567k 0.1567e-2mOutput:
1,567.0 1,567.0 1,567.0Input:
25.123kK 25.123m 2.5123e-00002GOutput:
25,123,000.0 25,123,000.0 25,123,000.0Input:
25.123kiKI 25.123Mi 2.5123e-00002Gi +.25123E-7EiOutput:
26,343,374.848 26,343,374.848 26,975,615.844352 28,964,846,960.23782Input:
-.25123e-34Vikki 2e-77gooGolsOutput:
-33,394.19493810444 2e+23Input:
9! 9!! 9!!! 9!!!! 9!!!!! 9!!!!!! 9!!!!!!! 9!!!!!!!! 9!!!!!!!!!Output:
362,880.0 945.0 162.0 45.0 36.0 27.0 18.0 9.0 9.0
Perl
#!/usr/bin/perl
use strict; # https://rosettacode.org/wiki/Numerical_and_alphabetical_suffixes
use warnings;
my %suffix = qw( k 1e3 m 1e6 g 1e9 t 1e12 p 1e15 e 1e18 z 1e21 y 1e24 x 1e27
w 1e30 v 1e33 u 1e36 ki 2**10 mi 2**20 gi 2**30 ti 2**40 pi 2**50 ei 2**60
zi 2**70 yi 2**80 xi 2**90 wi 2**100 vi 2**110 ui 2**120 );
local $" = ' '; # strange rule...
print "numbers = ${_}results = @{[ map suffix($_), split ]}\n\n" while <DATA>;
sub suffix
{
my ($value, $mods) = shift =~ tr/,//dr =~ /([+-]?[\d.]+(?:e[+-]\d+)?)(.*)/i;
$value *= $^R while $mods =~ /
PAIRs? (?{ 2 })
| SCO(re?)? (?{ 20 })
| DOZ(e(ns?)?)? (?{ 12 })
| GREATGR(o(ss?)?)? (?{ 1728 }) # must be before GRoss
| GR(o(ss?)?)? (?{ 144 })
| GOOGOLs? (?{ 10**100 })
| [kmgtpezyxwvu]i? (?{ eval $suffix{ lc $& } })
| !+ (?{ my $factor = $value;
$value *= $factor while ($factor -= length $&) > 1;
1 })
/gix;
return $value =~ s/(\..*)|\B(?=(\d\d\d)+(?!\d))/$1 || ','/ger;
}
__DATA__
2greatGRo 24Gros 288Doz 1,728pairs 172.8SCOre
1,567 +1.567k 0.1567e-2m
25.123kK 25.123m 2.5123e-00002G
25.123kiKI 25.123Mi 2.5123e-00002Gi +.25123E-7Ei
-.25123e-34Vikki 2e-77gooGols
9! 9!! 9!!! 9!!!! 9!!!!! 9!!!!!! 9!!!!!!! 9!!!!!!!! 9!!!!!!!!!
- Output:
numbers = 2greatGRo 24Gros 288Doz 1,728pairs 172.8SCOre results = 3,456 3,456 3,456 3,456 3,456 numbers = 1,567 +1.567k 0.1567e-2m results = 1,567 1,567 1,567 numbers = 25.123kK 25.123m 2.5123e-00002G results = 25,123,000 25,123,000 25,123,000 numbers = 25.123kiKI 25.123Mi 2.5123e-00002Gi +.25123E-7Ei results = 26,343,374.848 26,343,374.848 26,975,615.844352 28,964,846,960.2378 numbers = -.25123e-34Vikki 2e-77gooGols results = -33,394.1949381044 2e+23 numbers = 9! 9!! 9!!! 9!!!! 9!!!!! 9!!!!!! 9!!!!!!! 9!!!!!!!! 9!!!!!!!!! results = 362,880 945 162 45 36 27 18 9 9
Phix
Using bigatom to get the full precision needed for the tests (esp the "Vikki" one).
Note that comma-insertion was added to ba_sprintf() in version 0.8.0.
with javascript_semantics include builtins/bigatom.e {} = ba_scale(34) -- (min rqd for accuracy on the "Vikki" test) -- (the default is 25, not quite enough here) constant suffixes = {{"GREATGRoss",7,1728}, {"GOOGOLs",6,ba_new("1e100")}, {"SCOres",3,20}, {"DOZens",3,12}, {"GRoss",2,144}, {"PAIRs",4,2}, "KMGTPEZYXWVU"} function decode(string suffix) bigatom res = BA_ONE suffix = upper(suffix) while length(suffix)>0 do bool found = false for i=length(suffix) to 2 by -1 do for s=1 to length(suffixes)-1 do if i<=length(suffixes[s][1]) and i>=suffixes[s][2] and suffix[1..i]=upper(suffixes[s][1][1..i]) then res = ba_mul(res,suffixes[s][3]) suffix = suffix[i+1..$] found = true exit end if end for if found then exit end if end for if not found then integer k = find(suffix[1],suffixes[$]) if k=0 then ?9/0 end if if length(suffix)>=2 and suffix[2]='I' then res = ba_mul(res,ba_power(1024,k)) suffix = suffix[3..$] else res = ba_mul(res,ba_power(1000,k)) suffix = suffix[2..$] end if end if end while return res end function function facto(bigatom n, integer f) if f!=0 then bigatom nf = ba_sub(n,f) while ba_compare(nf,2)>=0 do n = ba_mul(n,nf) nf = ba_sub(nf,f) end while end if return n end function constant test_cases = """ 2greatGRo 24Gros 288Doz 1,728pairs 172.8SCOre 1,567 +1.567k 0.1567e-2m 25.123kK 25.123m 2.5123e-00002G 25.123kiKI 25.123Mi 2.5123e-00002Gi +.25123E-7Ei -.25123e-34Vikki 2e-77gooGols 9! 9!! 9!!! 9!!!! 9!!!!! 9!!!!!! 9!!!!!!! 9!!!!!!!! 9!!!!!!!!! 0.017k!! """ constant tests = split(substitute(test_cases,"\n"," "),no_empty:=true) for i=1 to length(tests) do string test = tests[i], suffix = "", facts = "" for f=length(test) to 1 by -1 do if test[f]!='!' then {test,facts} = {test[1..f],test[f+1..$]} exit end if end for for d=length(test) to 1 by -1 do integer digit = test[d] if digit>='0' and digit<='9' then {test,suffix} = {test[1..d],test[d+1..$]} exit end if end for bigatom n = ba_new(substitute(test,",","")) n = ba_mul(n,decode(suffix)) n = facto(n,length(facts)) string ns = ba_sprintf("%,B",n) printf(1,"%30s : %s\n",{tests[i],ns}) end for
- Output:
2greatGRo : 3,456 24Gros : 3,456 288Doz : 3,456 1,728pairs : 3,456 172.8SCOre : 3,456 1,567 : 1,567 +1.567k : 1,567 0.1567e-2m : 1,567 25.123kK : 25,123,000 25.123m : 25,123,000 2.5123e-00002G : 25,123,000 25.123kiKI : 26,343,374.848 25.123Mi : 26,343,374.848 2.5123e-00002Gi : 26,975,615.844352 +.25123E-7Ei : 28,964,846,960.237816578048 -.25123e-34Vikki : -33,394.194938104441474962344775423096782848 2e-77gooGols : 200,000,000,000,000,000,000,000 9! : 362,880 9!! : 945 9!!! : 162 9!!!! : 45 9!!!!! : 36 9!!!!!! : 27 9!!!!!!! : 18 9!!!!!!!! : 9 9!!!!!!!!! : 9 0.017k!! : 34,459,425
PureBasic
Structure minmult
min.i
mult.d
EndStructure
Structure suffix_entry
key.s
value.minmult
EndStructure
Structure metric_entry
key.s
value.d
EndStructure
Global Dim abbrevs.suffix_entry(5)
Global Dim metric.metric_entry(11)
Global Dim binary_metric.metric_entry(11)
Procedure initialize_data()
; Initialize abbrevs
abbrevs(0)\key = "PAIRs" : abbrevs(0)\value\min = 4 : abbrevs(0)\value\mult = 2
abbrevs(1)\key = "SCOres" : abbrevs(1)\value\min = 3 : abbrevs(1)\value\mult = 20
abbrevs(2)\key = "DOZens" : abbrevs(2)\value\min = 3 : abbrevs(2)\value\mult = 12
abbrevs(3)\key = "GRoss" : abbrevs(3)\value\min = 2 : abbrevs(3)\value\mult = 144
abbrevs(4)\key = "GREATGRoss" : abbrevs(4)\value\min = 7 : abbrevs(4)\value\mult = 1728
abbrevs(5)\key = "GOOGOLs" : abbrevs(5)\value\min = 6 : abbrevs(5)\value\mult = 1e100
; Initialize metric
metric(0)\key = "K" : metric(0)\value = 1e3
metric(1)\key = "M" : metric(1)\value = 1e6
metric(2)\key = "G" : metric(2)\value = 1e9
metric(3)\key = "T" : metric(3)\value = 1e12
metric(4)\key = "P" : metric(4)\value = 1e15
metric(5)\key = "E" : metric(5)\value = 1e18
metric(6)\key = "Z" : metric(6)\value = 1e21
metric(7)\key = "Y" : metric(7)\value = 1e24
metric(8)\key = "X" : metric(8)\value = 1e27
metric(9)\key = "W" : metric(9)\value = 1e30
metric(10)\key = "V" : metric(10)\value = 1e33
metric(11)\key = "U" : metric(11)\value = 1e36
; Initialize binary_metric
binary_metric(0)\key = "Ki" : binary_metric(0)\value = Pow(2, 10)
binary_metric(1)\key = "Mi" : binary_metric(1)\value = Pow(2, 20)
binary_metric(2)\key = "Gi" : binary_metric(2)\value = Pow(2, 30)
binary_metric(3)\key = "Ti" : binary_metric(3)\value = Pow(2, 40)
binary_metric(4)\key = "Pi" : binary_metric(4)\value = Pow(2, 50)
binary_metric(5)\key = "Ei" : binary_metric(5)\value = Pow(2, 60)
binary_metric(6)\key = "Zi" : binary_metric(6)\value = Pow(2, 70)
binary_metric(7)\key = "Yi" : binary_metric(7)\value = Pow(2, 80)
binary_metric(8)\key = "Xi" : binary_metric(8)\value = Pow(2, 90)
binary_metric(9)\key = "Wi" : binary_metric(9)\value = Pow(2, 100)
binary_metric(10)\key = "Vi" : binary_metric(10)\value = Pow(2, 110)
binary_metric(11)\key = "Ui" : binary_metric(11)\value = Pow(2, 120)
EndProcedure
Procedure.q fact(num.s, d.i)
Protected prod.q = 1
Protected n.i = Val(num), i.i
Select d
Case 1
For i = n To 1 Step -1
prod * i
Next
Case 2
For i = n To 1 Step -2
prod * i
Next
Case 3
For i = n To 1 Step -3
prod * i
Next
Default
i = n
While i > 0
prod * i
i - d
Wend
EndSelect
ProcedureReturn prod
EndProcedure
Procedure.s remove_commas(s.s)
Protected result.s = ""
Protected i.i
For i = 1 To Len(s)
If Mid(s, i, 1) <> "," : result + Mid(s, i, 1) : EndIf
Next
ProcedureReturn result
EndProcedure
Procedure.d parse(number.s)
Protected.i i, j, k
Protected.s num, suf, key
Protected.d result
; find index of last digit
For i = Len(number) - 1 To 0 Step -1
If Asc(Mid(number, i + 1, 1)) >= Asc("0") And Asc(Mid(number, i + 1, 1)) <= Asc("9") : Break : EndIf
Next
num = Left(number, i + 1)
num = ReplaceString(num, ",", "")
suf = UCase(Mid(number, i + 2))
If suf = "" : ProcedureReturn ValD(num) : EndIf
If Left(suf, 1) = "!" : ProcedureReturn fact(num, Len(suf)) : EndIf
For i = 0 To ArraySize(abbrevs())
key = UCase(abbrevs(i)\key)
If Left(key, Len(suf)) = suf And Len(suf) >= abbrevs(i)\value\min
ProcedureReturn ValD(num) * abbrevs(i)\value\mult
EndIf
Next
result = ValD(num)
For i = 1 To Len(suf)
For j = 0 To ArraySize(metric())
If Mid(suf, i, 1) = metric(j)\key
If i < Len(suf) And Mid(suf, i + 1, 1) = "I"
For k = 0 To ArraySize(binary_metric())
If binary_metric(k)\key = metric(j)\key + "i"
result * binary_metric(k)\value
i + 1
Break
EndIf
Next
Else
result * metric(j)\value
EndIf
Break
EndIf
Next
Next
ProcedureReturn result
EndProcedure
Procedure.s commatize(s.s)
Protected.s result = s
Protected.i dotPos = FindString(s, ".")
Protected.i i, startPos
; Limit to 6 decimal places
If dotPos : result = Left(s, dotPos + 7) : EndIf
dotPos = FindString(result, ".")
If dotPos = 0 : dotPos = Len(result) + 1 : EndIf
startPos = 1
If Left(result, 1) = "-" : startPos = 2 : EndIf
For i = dotPos - 3 To startPos Step -3
If i > startPos
result = InsertString(result, ",", i)
EndIf
Next
ProcedureReturn result
EndProcedure
Procedure process(Array numbers.s(1))
Protected i.i, res.d
Print("Numbers = ")
For i = 0 To ArraySize(numbers())
Print(numbers(i) + " ")
Next
Print(#CRLF$ + "Results = ")
For i = 0 To ArraySize(numbers())
res = parse(numbers(i))
Print(commatize(StrD(res)) + " ")
Next
PrintN(#CRLF$)
EndProcedure
If OpenConsole()
Dim numbers.s(4)
initialize_data()
numbers(0) = "2greatGRo"
numbers(1) = "24Gros"
numbers(2) = "288Doz"
numbers(3) = "1,728pairs"
numbers(4) = "172.8SCOre"
process(numbers())
Dim numbers.s(2)
numbers(0) = "1,567" : numbers(1) = "+1.567k" : numbers(2) = "0.1567e-2m"
process(numbers())
Dim numbers.s(2)
numbers(0) = "25.123kK" : numbers(1) = "25.123m" : numbers(2) = "2.5123e-00002G"
process(numbers())
Dim numbers.s(3)
numbers(0) = "25.123kiKI"
numbers(1) = "25.123Mi"
numbers(2) = "2.5123e-00002Gi"
numbers(3) = "+.25123E-7Ei"
process(numbers())
Dim numbers.s(1)
numbers(0) = "-.25123e-34Vikki" : numbers(1) = "2e-77gooGols"
process(numbers())
Dim numbers.s(8)
numbers(0) = "9!"
numbers(1) = "9!!"
numbers(2) = "9!!!"
numbers(3) = "9!!!!"
numbers(4) = "9!!!!!"
numbers(5) = "9!!!!!!"
numbers(6) = "9!!!!!!!"
numbers(7) = "9!!!!!!!!"
numbers(8) = "9!!!!!!!!!"
process(numbers())
PrintN(#CRLF$ + "Press ENTER to exit"): Input()
CloseConsole()
EndIf
- Output:
Numbers = 2greatGRo 24Gros 288Doz 1,728pairs 172.8SCOre Results = 3,456 3,456 3,456 3,456 3,456 Numbers = 1,567 +1.567k 0.1567e-2m Results = 1,567 1,567 1,567 Numbers = 25.123kK 25.123m 2.5123e-00002G Results = 25,123,000 25,123,000 25,123,000 Numbers = 25.123kiKI 25.123Mi 2.5123e-00002Gi +.25123E-7Ei Results = 26,343,374.8480000 26,343,374.8480000 26,975,615.8443519 28,964,846,960.2378158 Numbers = -.25123e-34Vikki 2e-77gooGols Results = -33,394.1949381 199,999,999,999,999,983,222,784 Numbers = 9! 9!! 9!!! 9!!!! 9!!!!! 9!!!!!! 9!!!!!!! 9!!!!!!!! 9!!!!!!!!! Results = 362,880 945 162 45 36 27 18 9 9
Python
from functools import reduce
from operator import mul
from decimal import *
getcontext().prec = MAX_PREC
def expand(num):
suffixes = [
# (name, min_abbreviation_length, base, exponent)
('greatgross', 7, 12, 3),
('gross', 2, 12, 2),
('dozens', 3, 12, 1),
('pairs', 4, 2, 1),
('scores', 3, 20, 1),
('googols', 6, 10, 100),
('ki', 2, 2, 10),
('mi', 2, 2, 20),
('gi', 2, 2, 30),
('ti', 2, 2, 40),
('pi', 2, 2, 50),
('ei', 2, 2, 60),
('zi', 2, 2, 70),
('yi', 2, 2, 80),
('xi', 2, 2, 90),
('wi', 2, 2, 100),
('vi', 2, 2, 110),
('ui', 2, 2, 120),
('k', 1, 10, 3),
('m', 1, 10, 6),
('g', 1, 10, 9),
('t', 1, 10, 12),
('p', 1, 10, 15),
('e', 1, 10, 18),
('z', 1, 10, 21),
('y', 1, 10, 24),
('x', 1, 10, 27),
('w', 1, 10, 30)
]
num = num.replace(',', '').strip().lower()
if num[-1].isdigit():
return float(num)
for i, char in enumerate(reversed(num)):
if char.isdigit():
input_suffix = num[-i:]
num = Decimal(num[:-i])
break
if input_suffix[0] == '!':
return reduce(mul, range(int(num), 0, -len(input_suffix)))
while len(input_suffix) > 0:
for suffix, min_abbrev, base, power in suffixes:
if input_suffix[:min_abbrev] == suffix[:min_abbrev]:
for i in range(min_abbrev, len(input_suffix) + 1):
if input_suffix[:i+1] != suffix[:i+1]:
num *= base ** power
input_suffix = input_suffix[i:]
break
break
return num
test = "2greatGRo 24Gros 288Doz 1,728pairs 172.8SCOre\n\
1,567 +1.567k 0.1567e-2m\n\
25.123kK 25.123m 2.5123e-00002G\n\
25.123kiKI 25.123Mi 2.5123e-00002Gi +.25123E-7Ei\n\
-.25123e-34Vikki 2e-77gooGols\n\
9! 9!! 9!!! 9!!!! 9!!!!! 9!!!!!! 9!!!!!!! 9!!!!!!!! 9!!!!!!!!!"
for test_line in test.split("\n"):
test_cases = test_line.split()
print("Input:", ' '.join(test_cases))
print("Output:", ' '.join(format(result, ',f').strip('0').strip('.') for result in map(expand, test_cases)))
- Output:
Input: 2greatGRo 24Gros 288Doz 1,728pairs 172.8SCOre Output: 3,456 3,456 3,456 3,456 3,456 Input: 1,567 +1.567k 0.1567e-2m Output: 1,567 1,567 1,567 Input: 25.123kK 25.123m 2.5123e-00002G Output: 25,123,000 25,123,000 25,123,000 Input: 25.123kiKI 25.123Mi 2.5123e-00002Gi +.25123E-7Ei Output: 26,343,374.848 26,343,374.848 26,975,615.844352 28,964,846,960.237816578048 Input: -.25123e-34Vikki 2e-77gooGols Output: -33,394.194938104441474962344775423096782848 200,000,000,000,000,000,000,000 Input: 9! 9!! 9!!! 9!!!! 9!!!!! 9!!!!!! 9!!!!!!! 9!!!!!!!! 9!!!!!!!!! Output: 362,880 945 162 45 36 27 18 9 9
Raku
(formerly Perl 6)
Scientific notation, while supported in Raku, is limited to IEEE-754 64bit accuracy so there is some rounding on values using it. Implements a custom "high precision" conversion routine.
Unfortunately, this suffix routine is of limited use for practical everyday purposes. It focuses on handling excessively large and archaic units (googol, greatgross) and completely ignores or makes unusable (due to forcing case insensitivity) many common current ones: c(centi), m(milli), μ(micro). Ah well.
Note: I am blatantly and deliberately ignoring the task guidelines for formatting the output. It has no bearing on the core of the task. If you really, really, REALLY want to see badly formatted output, uncomment the last line.
use Rat::Precise;
my $googol = 10**100;
«PAIRs 2 SCOres 20 DOZens 12 GRoss 144 GREATGRoss 1728 GOOGOLs $googol»
~~ m:g/ ((<.:Lu>+) <.:Ll>*) \s+ (\S+) /;
my %abr = |$/.map: {
my $abbrv = .[0].Str.fc;
my $mag = +.[1];
|map { $abbrv.substr( 0, $_ ) => $mag },
.[0][0].Str.chars .. $abbrv.chars
}
my %suffix = flat %abr,
(<K M G T P E Z Y X W V U>».fc Z=> (1000, * * 1000 … *)),
(<Ki Mi Gi Ti Pi Ei Zi Yi Xi Wi Vi Ui>».fc Z=> (1024, * * 1024 … *));
my $reg = %suffix.keys.join('|');
sub comma ($i is copy) {
my $s = $i < 0 ?? '-' !! '';
my ($whole, $frac) = $i.split('.');
$frac = $frac.defined ?? ".$frac" !! '';
$s ~ $whole.abs.flip.comb(3).join(',').flip ~ $frac
}
sub units (Str $str) {
$str.fc ~~ /^(.+?)(<alpha>*)('!'*)$/;
my ($val, $unit, $fact) = $0, $1.Str.fc, $2.Str;
$val.=subst(',', '', :g);
if $val ~~ m:i/'e'/ {
my ($m,$e) = $val.split(/<[eE]>/);
$val = ($e < 0)
?? $m * FatRat.new(1,10**-$e)
!! $m * 10**$e;
}
my @suf = $unit;
unless %suffix{$unit}:exists {
$unit ~~ /(<$reg>)+/;
@suf = $0;
}
my $ret = $val<>;
$ret = [*] $ret, |@suf.map: { %suffix{$_} } if @suf[0];
$ret = [*] ($ret, * - $fact.chars …^ * < 2) if $fact.chars;
$ret.?precise // $ret
}
my $test = q:to '===';
2greatGRo 24Gros 288Doz 1,728pairs 172.8SCOre
1,567 +1.567k 0.1567e-2m
25.123kK 25.123m 2.5123e-00002G
25.123kiKI 25.123Mi 2.5123e-00002Gi +.25123E-7Ei
-.25123e-34Vikki 2e-77gooGols
9! 9!! 9!!! 9!!!! 9!!!!! 9!!!!!! 9!!!!!!! 9!!!!!!!! 9!!!!!!!!!
.017k!!
===
printf "%16s: %s\n", $_, comma .&units for $test.words;
# Task required stupid layout
# say "\n In: $_\nOut: ", .words.map({comma .&units}).join(' ') for $test.lines;
- Output:
2greatGRo: 3,456 24Gros: 3,456 288Doz: 3,456 1,728pairs: 3,456 172.8SCOre: 3,456 1,567: 1,567 +1.567k: 1,567 0.1567e-2m: 1,567 25.123kK: 25,123,000 25.123m: 25,123,000 2.5123e-00002G: 25,123,000 25.123kiKI: 26,343,374.848 25.123Mi: 26,343,374.848 2.5123e-00002Gi: 26,975,615.844352 +.25123E-7Ei: 28,964,846,960.237816578048 -.25123e-34Vikki: -33,394.194938104441474962344775423096782848 2e-77gooGols: 200,000,000,000,000,000,000,000 9!: 362,880 9!!: 945 9!!!: 162 9!!!!: 45 9!!!!!: 36 9!!!!!!: 27 9!!!!!!!: 18 9!!!!!!!!: 9 9!!!!!!!!!: 9 .017k!!: 34,459,425
REXX
/*REXX pgm converts numbers (with commas) with suffix multipliers──►pure decimal numbers*/
numeric digits 2000 /*allow the usage of ginormous numbers.*/
@.=; @.1= '2greatGRo 24Gros 288Doz 1,728pairs 172.8SCOre'
@.2= '1,567 +1.567k 0.1567e-2m'
@.3= '25.123kK 25.123m 2.5123e-00002G'
@.4= '25.123kiKI 25.123Mi 2.5123e-00002Gi +.25123E-7Ei'
@.5= '-.25123e-34Vikki 2e-77gooGols'
@.6= 9! 9!! 9!!! 9!!!! 9!!!!! 9!!!!!! 9!!!!!!! 9!!!!!!!! 9!!!!!!!!!
parse arg x /*obtain optional arguments from the CL*/
if x\=='' then do; @.2=; @.1=x /*use the number(s) specified on the CL*/
end /*allow user to specify their own list.*/
/* [↓] handle a list or multiple lists*/
do n=1 while @.n\==''; $= /*process each of the numbers in lists.*/
say 'numbers= ' @.n /*echo the original arg to the terminal*/
do j=1 for words(@.n); y= word(@.n, j) /*obtain a single number from the input*/
$= $ ' 'commas( num(y) ) /*process a number; add result to list.*/
end /*j*/ /* [↑] add commas to number if needed.*/
/* [↑] add extra blank betweenst nums.*/
say ' result= ' strip($); say /*echo the result(s) to the terminal. */
end /*n*/ /* [↑] elide the pre-pended blank. */
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
isInt: return datatype( arg(1), 'Whole') /*return 1 if arg is an integer, or 0 */
isNum: return datatype( arg(1), 'Number') /* " " " " " a number. " " */
p: return word( arg(1), 1) /*pick 1st argument or 2nd argument. */
ser: say; say '***error*** ' arg(1); say; exit 13
shorten:procedure; parse arg a,n; return left(a, max(0, length(a) - p(n 1) ) )
/*──────────────────────────────────────────────────────────────────────────────────────*/
$fact!: procedure; parse arg x _ .; L= length(x); n= L - length(strip(x, 'T', "!") )
if n<=-n | _\=='' | arg()\==1 then return x; z= left(x, L - n)
if z<0 | \isInt(z) then return x; return $fact(z, n)
/*──────────────────────────────────────────────────────────────────────────────────────*/
$fact: procedure; parse arg x _ .; arg ,n ! .; n= p(n 1); if \isInt(n) then n= 0
if x<-n | \isInt(x) |n<1 | _||!\=='' |arg()>2 then return x||copies("!",max(1,n))
s= x // n; if s==0 then s= n /*compute where to start multiplying. */
!= 1 /*the initial factorial product so far.*/
do j=s to x by n; != !*j /*perform the actual factorial product.*/
end /*j*/ /*{operator // is REXX's ÷ remainder}*/
return ! /* [↑] handles any level of factorial.*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
$sfxa: parse arg u,s 1 c,m; upper u c /*get original version & upper version.*/
if pos( left(s, 2), u)\==0 then do j=length(s) to compare(s, c)-1 by -1
if right(u, j) \== left(c, j) then iterate
_= left(u, length(u) - j) /*get the num.*/
if isNum(_) then return m * _ /*good suffix.*/
leave /*return as is*/
end
return arg(1) /* [↑] handles an alphabetic suffixes.*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
$sfx!: parse arg y; if right(y, 1)=='!' then y= $fact!(y)
if \isNum(y) then y=$sfxz(); if isNum(y) then return y; return $sfxm(y)
/*──────────────────────────────────────────────────────────────────────────────────────*/
$sfxm: parse arg z 1 w; upper w; @= 'KMGTPEZYXWVU'; b= 1000
if right(w, 1)=='I' then do; z= shorten(z); w= z; upper w; b= 1024
end
_= pos( right(w, 1), @); if _==0 then return arg(1)
n= shorten(z); r= num(n, , 1); if isNum(r) then return r * b**_
return arg(1) /* [↑] handles metric or binary suffix*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
$sfxz: return $sfxa( $sfxa( $sfxa( $sfxa( $sfxa( $sfxa(y, 'PAIRs', 2), 'DOZens', 12), ,
'SCores', 20), 'GREATGRoss', 1728), 'GRoss', 144), 'GOOGOLs', 1e100)
/*──────────────────────────────────────────────────────────────────────────────────────*/
commas: procedure; parse arg _; n= _'.9'; #= 123456789; b= verify(n, #, "M")
e= verify(n, #'0', , verify(n, #"0.", 'M') ) - 4 /* [↑] add commas.*/
do j=e to b by -3; _= insert(',', _, j); end /*j*/; return _
/*──────────────────────────────────────────────────────────────────────────────────────*/
num: procedure; parse arg x .,,q; if x=='' then return x
if isNum(x) then return x/1; x= space( translate(x, , ','), 0)
if \isNum(x) then x= $sfx!(x); if isNum(x) then return x/1
if q==1 then return x
if q=='' then call ser "argument isn't numeric or doesn't have a legal suffix:" x
- output when using the default inputs:
numbers= 2greatGRo 24Gros 288Doz 1,728pairs 172.8SCOre result= 3,456 3,456 3,456 3,456 3,456 numbers= 1,567 +1.567k 0.1567e-2m result= 1,567 1,567 1,567 numbers= 25.123kK 25.123m 2.5123e-00002G result= 25,123,000 25,123,000 25,123,000 numbers= 25.123kiKI 25.123Mi 2.5123e-00002Gi +.25123E-7Ei result= 26,343,374.848 26,343,374.848 26,975,615.844352 28,964,846,960.237816578048 numbers= -.25123e-34Vikki 2e-77gooGols result= -33,394.194938104441474962344775423096782848 200,000,000,000,000,000,000,000 numbers= 9! 9!! 9!!! 9!!!! 9!!!!! 9!!!!!! 9!!!!!!! 9!!!!!!!! 9!!!!!!!!! result= 362,880 945 162 45 36 27 18 9 9
Rust
use itertools::Itertools;
use std::cmp::min;
use std::str::FromStr;
// (name, minimum abbreviation length, base, power of base)
const SUFFIXES: [(&str, usize, usize, u32); 28] = [
("greatgross", 7, 12, 3),
("gross", 2, 12, 2),
("dozens", 3, 12, 1),
("pairs", 4, 2, 1),
("scores", 3, 20, 1),
("googols", 6, 10, 100),
("ki", 2, 2, 10),
("mi", 2, 2, 20),
("gi", 2, 2, 30),
("ti", 2, 2, 40),
("pi", 2, 2, 50),
("ei", 2, 2, 60),
("zi", 2, 2, 70),
("yi", 2, 2, 80),
("xi", 2, 2, 90),
("wi", 2, 2, 100),
("vi", 2, 2, 110),
("ui", 2, 2, 120),
("k", 1, 10, 3),
("m", 1, 10, 6),
("g", 1, 10, 9),
("t", 1, 10, 12),
("p", 1, 10, 15),
("e", 1, 10, 18),
("z", 1, 10, 21),
("y", 1, 10, 24),
("x", 1, 10, 27),
("w", 1, 10, 30),
];
fn expand(input: &str) -> String {
let num = input.replace(",", "").trim().to_lowercase().to_string();
let len = num.len();
let numchars = num.chars().collect_vec();
if numchars[len - 1].is_numeric() {
return f64::from_str(num.as_str()).unwrap().to_string();
}
// find end of initial numeric portion
let mut pos = num
.find(|c: char| !c.is_numeric() && !".+-".contains(c))
.unwrap_or(len);
// if factorial, calculate
if pos < len && &num[pos..=pos] == "!" {
let step = len - pos;
let i = i64::from_str(&num[..pos]).unwrap();
return (1..=i)
.rev()
.step_by(step)
.fold(1, |p, f| f * p)
.to_string();
}
// if we have an exponential notation number, include that portion
if pos < num.len() - 2
&& (numchars[pos] == 'e' || numchars[pos] == 'E')
&& (numchars[pos + 1].is_numeric() || "+-".contains(numchars[pos + 1]))
{
let mut rnumchars = numchars.clone();
rnumchars.reverse();
pos = num.len()
- rnumchars
.iter()
.enumerate()
.find(|(_i, c)| c.is_numeric())
.unwrap()
.0;
}
let mut fnum = f64::from_str(&num[..pos]).unwrap();
let mut extra_digits = 0_usize;
let mut input_suffix = &num[pos..];
while !input_suffix.is_empty() {
for (suffix, min_abbrev, base, power) in SUFFIXES {
match input_suffix.find(&suffix[..min_abbrev]) {
Some(start) => {
if start == 0 {
if base == 10 && power > 30 {
extra_digits = power as usize;
} else {
fnum *= (base as i128).pow(power) as f64;
}
let min_len = min(input_suffix.len(), suffix.len());
let ichars = input_suffix.chars().collect_vec();
let schars = suffix.chars().collect_vec();
for i in 0..=min_len {
if i == min_len || ichars[i] != schars[i] {
input_suffix = &input_suffix[i..];
break;
}
}
break;
}
}
None => {}
}
}
}
if fnum > 1.0 && (fnum - fnum.round()).abs() < f64::EPSILON {
let zeros = "0".repeat(extra_digits);
return (fnum.round() as i128).to_string() + zeros.as_str();
}
for _ in 0..extra_digits {
// may prevent overflow
fnum *= 10 as f64;
}
return fnum.to_string();
}
fn main() {
let test_cases = (r#"
2greatGRo 24Gros 288Doz 1,728pairs 172.8SCOre
1,567 +1.567k 0.1567e-2m
25.123kK 25.123m 2.5123e-00002G
25.123kiKI 25.123Mi 2.5123e-00002Gi +.25123E-7Ei
-.25123e-34Vikki 2e-77gooGols
9! 9!! 9!!! 9!!!! 9!!!!! 9!!!!!! 9!!!!!!! 9!!!!!!!! 9!!!!!!!!!
"#)
.split("\n")
.collect_vec();
for line in test_cases.iter().filter(|x| !x.trim().is_empty()) {
let results = line
.trim()
.split_whitespace()
.map(|s| expand(s))
.join(" ");
println!("Input: {}\nOutput: {}\n", line, results);
}
}
- Output:
Input: 2greatGRo 24Gros 288Doz 1,728pairs 172.8SCOre Output: 3456 3456 3456 3456 3456 Input: 1,567 +1.567k 0.1567e-2m Output: 1567 1567 1567 Input: 25.123kK 25.123m 2.5123e-00002G Output: 25123000 25123000 25123000 Input: 25.123kiKI 25.123Mi 2.5123e-00002Gi +.25123E-7Ei Output: 26343374.848 26343374.848 26975615.844352 28964846960.237816 Input: -.25123e-34Vikki 2e-77gooGols Output: -33394.19493810444 200000000000000200000000 Input: 9! 9!! 9!!! 9!!!! 9!!!!! 9!!!!!! 9!!!!!!! 9!!!!!!!! 9!!!!!!!!! Output: 362880 945 162 45 36 27 18 9 9
Wren
import "./big" for BigRat
import "./str" for Str
import "./fmt" for Fmt
var abbrevs = {
"PAIRs": [4, 2], "SCOres": [3, 20], "DOZens": [3, 12],
"GRoss": [2, 144], "GREATGRoss": [7, 1728], "GOOGOLs": [6, 1e100]
}
var metric = {
"K": 1e3, "M": 1e6, "G": 1e9, "T": 1e12, "P": 1e15, "E": 1e18,
"Z": 1e21, "Y": 1e24, "X": 1e27, "W": 1e30, "V": 1e33, "U": 1e36
}
var b = Fn.new { |e| BigRat.two.pow(e) }
var binary = {
"Ki": b.call(10), "Mi": b.call(20), "Gi": b.call(30), "Ti": b.call(40),
"Pi": b.call(50), "Ei": b.call(60), "Zi": b.call(70), "Yi": b.call(80),
"Xi": b.call(90), "Wi": b.call(100), "Vi": b.call(110), "Ui": b.call(120)
}
var googol = BigRat.fromDecimal("1e100")
var fact = Fn.new { |num, d|
var prod = 1
var n = Num.fromString(num)
var i = n
while (i > 0) {
prod = prod * i
i = i - d
}
return prod
}
var parse = Fn.new { |number|
// find index of last digit
var i = number.count - 1
while (i >= 0) {
if (48 <= number.bytes[i] && number.bytes[i] <= 57) break
i = i - 1
}
var num = number[0..i]
num = num.replace(",", "") // get rid of any commas
var suf = Str.upper(number[i+1..-1])
if (suf == "") return BigRat.fromDecimal(num)
if (suf[0] == "!") {
var prod = fact.call(num, suf.count)
return BigRat.new(prod)
}
for (me in abbrevs) {
var kk = Str.upper(me.key)
if (kk.startsWith(suf) && suf.count >= me.value[0]) {
var t1 = BigRat.fromDecimal(num)
var t2 = (me.key != "GOOGOLS") ? BigRat.fromDecimal(me.value[1]) : googol
return t1 * t2
}
}
var bf = BigRat.fromDecimal(num)
for (me in metric) {
var j = 0
while (j < suf.count) {
if (me.key == suf[j]) {
if (j < suf.count-1 && suf[j+1] == "I") {
bf = bf * binary[me.key + "i"]
j = j + 1
} else {
bf = bf * me.value
}
}
j = j + 1
}
}
return bf
}
var process = Fn.new { |numbers|
System.write("numbers = ")
for (number in numbers) Fmt.write("$s ", number)
System.write("\nresults = ")
for (number in numbers) {
var res = parse.call(number)
if (res.isInteger) {
Fmt.write("$,s ", res.toDecimal(50))
} else {
var sres = Fmt.swrite("$,s", res.truncate.toDecimal)
Fmt.write("$s ", sres + res.fraction.abs.toDecimal(50)[1..-1])
}
}
System.print("\n")
}
var numbers = ["2greatGRo", "24Gros", "288Doz", "1,728pairs", "172.8SCOre"]
process.call(numbers)
numbers = ["1,567", "+1.567k", "0.1567e-2m"]
process.call(numbers)
numbers = ["25.123kK", "25.123m", "2.5123e-00002G"]
process.call(numbers)
numbers = ["25.123kiKI", "25.123Mi", "2.5123e-00002Gi", "+.25123E-7Ei"]
process.call(numbers)
numbers = ["-.25123e-34Vikki", "2e-77gooGols"]
process.call(numbers)
numbers = ["9!", "9!!", "9!!!", "9!!!!", "9!!!!!", "9!!!!!!", "9!!!!!!!", "9!!!!!!!!", "9!!!!!!!!!"]
process.call(numbers)
- Output:
numbers = 2greatGRo 24Gros 288Doz 1,728pairs 172.8SCOre results = 3,456 3,456 3,456 3,456 3,456 numbers = 1,567 +1.567k 0.1567e-2m results = 1,567 1,567 1,567 numbers = 25.123kK 25.123m 2.5123e-00002G results = 25,123,000 25,123,000 25,123,000 numbers = 25.123kiKI 25.123Mi 2.5123e-00002Gi +.25123E-7Ei results = 26,343,374.848 26,343,374.848 26,975,615.844352 28,964,846,960.237816578048 numbers = -.25123e-34Vikki 2e-77gooGols results = -33,394.194938104441474962344775423096782848 200,000,000,000,000,000,000,000 numbers = 9! 9!! 9!!! 9!!!! 9!!!!! 9!!!!!! 9!!!!!!! 9!!!!!!!! 9!!!!!!!!! results = 362,880 945 162 45 36 27 18 9 9
zkl
GNU Multiple Precision Arithmetic Library (big ints)
Floats are limited to 64 bit IEEE754. Error checking is nonexistent.
var [const] BI=Import.lib("zklBigNum"); // GMP
var kRE,kD, aRE,aD;
kRE,kD = ki();
aRE,aD = abrevCreate();
fcn naSuffixes(numStr){
var [const]
numRE=RegExp(0'^([+-]*\.*\d+[.]*\d*E*[+-]*\d*)^),
bangRE=RegExp(0'^(!+)^);
nstr:=(numStr - " ,").toUpper();
numRE.search(nstr);
nstr,r := nstr[numRE.matched[0][1],*], numRE.matched[1];
if(r.matches("*[.E]*")) r=r.toFloat(); // arg!
if(r.matches("*[.E]*")) r=r.toFloat(); // arg!
else r=BI(r);
reg z;
do{
z=nstr; // use this to see if we actually did anything
if(aRE.search(nstr)){
ns,k := aRE.matched; // ((0,3),"SCO")
re,b := aD[k]; // (RegExp("R|RE|RES"),BI(20)),
nstr = nstr[ns[1],*];
if(re.search(nstr)) nstr=nstr[re.matched[0][1],*]; # remove abbrev tail
r=r*b;
continue;
}else if(kRE.search(nstr)){
r*=kD[kRE.matched[1]]; // "K":1000 ...
nstr=nstr[kRE.matched[0][1],*];
continue;
}else if(bangRE.search(nstr)){ // floats are converted to int
n,k,z := r.toInt(), bangRE.matched[0][1], n - k;
r,nstr = BI(n), nstr[k,*];
while(z>0){ r.mul(z); z-=k; }
continue;
}
}while(nstr and z!=nstr);
r
}
fcn ki{ // case insensitive: k, ki,
ss:="K M G T P E Z Y X W V U".split();
d:=Dictionary();
ss.zipWith(d.add,[3..3*(ss.len()),3].apply(BI(10).pow)); # E:1e+18
ss.apply("append","I")
.zipWith(d.add,[10..10*(ss.len()),10].apply(BI(2).pow)); # EI:1.15292e+18
re:="([%s]I\\?)".fmt(ss.concat()); // "([KMGTPEZYXWVU]I\?)"
return(RegExp(re),d);
}
fcn abrevCreate{
var upDown=RegExp("([A-Z]+)(.*)");
s:="PAIRs 2; SCOres 20; DOZens 12; GREATGRoss 1728; GRoss 144; GOOGOLs 10e100".split(";");
abrevs,re := Dictionary(), Sink(String);
foreach an in (s){
a,n := an.split();
upDown.search(a);
u,d := upDown.matched[1,2];
d=d.len().pump(List, // "R|RE|RES"
'+(1),d.get.fp(0),"toUpper").reverse().concat("|");
abrevs.add(u,T(RegExp(d),BI(n)));
re.write(u," ");
}
// "PAIR|SCO|DOZ|GR|GREATGR|GOOGOL"
re=RegExp("(%s)".fmt(re.close().strip().replace(" ","|")));
return(re,abrevs);
}
foreach na in (T("2greatGRo", "24Gros", "288Doz", "1,728pairs", "172.8SCOre",
"1,567", "+1.567k", "0.1567e-2m",
"25.123kK", "25.123m", "2.5123e-00002G",
"25.123kiKI", "25.123Mi", "2.5123e-00002Gi", "+.25123E-7Ei",
"-.25123e-34Vikki", "2e-77gooGols",
"9!", "9!!", "9!!!", "9!!!!", "9!!!!!", "9!!!!!!",
"9!!!!!!!", "9!!!!!!!!", "9!!!!!!!!!",
"9!!!!!!!!!k", ".017k!!", "4 dozensK", "2 dozen pairs")){
if((r:=naSuffixes(na)).isType(Float)) println("%16s : %,f".fmt(na,r));
else println("%16s : %,d".fmt(na,r));
}
- Output:
2greatGRo : 3,456 24Gros : 3,456 288Doz : 3,456 1,728pairs : 3,456 172.8SCOre : 3,456.000000 1,567 : 1,567 +1.567k : 1,567.000000 0.1567e-2m : 1,567.000000 25.123kK : 25,123,000.000000 25.123m : 25,123,000.000000 2.5123e-00002G : 25,123,000.000000 25.123kiKI : 26,343,374.848000 25.123Mi : 26,343,374.848000 2.5123e-00002Gi : 26,975,615.844352 +.25123E-7Ei : 28,964,846,960.237816 -.25123e-34Vikki : -33,394.194938 2e-77gooGols : 1,999,999,999,999,999,698,010,112.000000 9! : 362,880 9!! : 945 9!!! : 162 9!!!! : 45 9!!!!! : 36 9!!!!!! : 27 9!!!!!!! : 18 9!!!!!!!! : 9 9!!!!!!!!! : 9 9!!!!!!!!!k : 9,000 .017k!! : 34,459,425 4 dozensK : 48,000 2 dozen pairs : 48