Jump to content

Suffixation of decimal numbers: Difference between revisions

Rename Perl 6 -> Raku, alphabetize, minor clean-up
(Rename Perl 6 -> Raku, alphabetize, minor clean-up)
Line 310:
new number = 1000U
</pre>
 
 
=={{header|Julia}}==
Line 479 ⟶ 478:
+16777216 B : 16Mi
1.2e101 G : 12googol
347,344 M -2 : 300K
1122334455 Q : What we have here is a failure to communicate...</pre>
 
=={{header|Perl 6}}==
{{works with|Rakudo|2018.09}}
Pass in a number string, optionally a type, and optionally the number of digits to round to.
 
The types supported are B, M & G for binary, metric or gigantic. (At this point, the only gigantic unit is googol, so maybe it stands for googol. ¯\_(ツ)_/¯ )
 
If no type is specified, M (metric) is assumed.
 
If you desire the number to be rounded, pass in a number representing the placed past the decimal to round to. If you pass in a negative number for rounding, it will round to a negative number of places past the decimal.
 
<lang perl6>sub sufficate ($val is copy, $type is copy = 'M', $round is copy = Any) {
if +$type ~~ Int { $round = $type; $type = 'M' }
my $s = '';
if $val.substr(0,1) eq '-' { $s = '-'; $val.=substr(1) }
$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 %s = do given $type {
when 'M' { <K M G T P E Z Y X W V U> Z=> (1000, * * 1000 … *) }
when 'B' { <Ki Mi Gi Ti Pi Ei Zi Yi Xi Wi Vi Ui> Z=> (1024, * * 1024 … *) }
when 'G' { googol => 10**100 }
default { return 'What we have here is a failure to communicate...' }
}
my $k = do given $val {
when .abs < (my $m = min %s.values) { %s.first( *.value == $m ).key };
when .abs > (my $x = max %s.values) { %s.first( *.value == $x ).key };
default { %s.sort(*.value).first({$val.abs/%s{$_.key} < min %s.values}).key}
}
$round.defined
?? $s ~ comma(($val.abs/%s{$k}).round(10**-$round)) ~ $k
!! $s ~ comma($val.abs/%s{$k}) ~ $k
}
 
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
}
 
## TESTING
 
my @tests =
'87,654,321',
'-998,877,665,544,332,211,000 3',
'+112,233 0',
'16,777,216 1',
'456,789,100,000,000',
'456,789,100,000,000 M 2',
'456,789,100,000,000 B 5',
'456,789,100,000.000e+00 M 0',
'+16777216 B',
'1.2e101 G',
"{run('df', '/', :out).out.slurp.words[10] * 1024} B 2", # Linux df returns Kilobytes by default
'347,344 M -2', # round to -2 past the decimal
'1122334455 Q', # bad unit type example
;
 
printf "%33s : %s\n", $_, sufficate(|.words) for @tests;</lang>
{{out}}
<pre> 87,654,321 : 87.654321M
-998,877,665,544,332,211,000 3 : -998.878E
+112,233 0 : 112K
16,777,216 1 : 16.8M
456,789,100,000,000 : 456.7891T
456,789,100,000,000 M 2 : 456.79T
456,789,100,000,000 B 5 : 415.44727Ti
456,789,100,000.000e+00 M 0 : 457G
+16777216 B : 16Mi
1.2e101 G : 12googol
703674818560 B 2 : 655.35Gi
347,344 M -2 : 300K
1122334455 Q : What we have here is a failure to communicate...</pre>
Line 642 ⟶ 563:
10 : 10
</pre>
 
=={{header|Python}}==
{{works with|cpython|3.7.3}}
Tested in Python 3.7.3<br />
Chose 3 places after decimal (where applicable) as default rounding precision. Number to suffize taken as a string. There are some edge cases where this fails due to binary arithmetic differing from decimal arithmetic and things not rounding nicely.
<lang python>
import math
import os
 
 
def suffize(num, digits=None, base=10):
suffixes = ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 'X', 'W', 'V', 'U', 'googol']
 
exponent_distance = 10 if base == 2 else 3
num = num.strip().replace(',', '')
num_sign = num[0] if num[0] in '+-' else ''
 
num = abs(float(num))
 
if base == 10 and num >= 1e100:
suffix_index = 13
num /= 1e100
elif num > 1:
magnitude = math.floor(math.log(num, base))
suffix_index = min(math.floor(magnitude / exponent_distance), 12)
num /= base ** (exponent_distance * suffix_index)
else:
suffix_index = 0
 
if digits is not None:
num_str = f'{num:.{digits}f}'
else:
num_str = f'{num:.3f}'.strip('0').strip('.')
 
return num_sign + num_str + suffixes[suffix_index] + ('i' if base == 2 else '')
 
 
tests = [('87,654,321',),
('-998,877,665,544,332,211,000', 3),
('+112,233', 0),
('16,777,216', 1),
('456,789,100,000,000', 2),
('456,789,100,000,000', 2, 10),
('456,789,100,000,000', 5, 2),
('456,789,100,000.000e+00', 0, 10),
('+16777216', None, 2),
('1.2e101',)]
 
for test in tests:
print(' '.join(str(i) for i in test) + ' : ' + suffize(*test))
</lang>
 
{{out}}
<pre>
87,654,321 : 87.654M
-998,877,665,544,332,211,000 3 : -998.878E
+112,233 0 : +112K
16,777,216 1 : 16.8M
456,789,100,000,000 2 : 456.79T
456,789,100,000,000 2 10 : 456.79T
456,789,100,000,000 5 2 : 415.44727Ti
456,789,100,000.000e+00 0 10 : 457G
+16777216 None 2 : +16Mi
1.2e101 : 12googol
</pre>
 
=={{header|Raku}}==
(formerly Perl 6)
{{works with|Rakudo|2018.09}}
Pass in a number string, optionally a type, and optionally the number of digits to round to.
 
The types supported are B, M & G for binary, metric or gigantic. (At this point, the only gigantic unit is googol, so maybe it stands for googol. ¯\_(ツ)_/¯ )
 
If no type is specified, M (metric) is assumed.
 
If you desire the number to be rounded, pass in a number representing the placed past the decimal to round to. If you pass in a negative number for rounding, it will round to a negative number of places past the decimal.
 
<lang perl6>sub sufficate ($val is copy, $type is copy = 'M', $round is copy = Any) {
if +$type ~~ Int { $round = $type; $type = 'M' }
my $s = '';
if $val.substr(0,1) eq '-' { $s = '-'; $val.=substr(1) }
$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 %s = do given $type {
when 'M' { <K M G T P E Z Y X W V U> Z=> (1000, * * 1000 … *) }
when 'B' { <Ki Mi Gi Ti Pi Ei Zi Yi Xi Wi Vi Ui> Z=> (1024, * * 1024 … *) }
when 'G' { googol => 10**100 }
default { return 'What we have here is a failure to communicate...' }
}
my $k = do given $val {
when .abs < (my $m = min %s.values) { %s.first( *.value == $m ).key };
when .abs > (my $x = max %s.values) { %s.first( *.value == $x ).key };
default { %s.sort(*.value).first({$val.abs/%s{$_.key} < min %s.values}).key}
}
$round.defined
?? $s ~ comma(($val.abs/%s{$k}).round(10**-$round)) ~ $k
!! $s ~ comma($val.abs/%s{$k}) ~ $k
}
 
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
}
 
## TESTING
 
my @tests =
'87,654,321',
'-998,877,665,544,332,211,000 3',
'+112,233 0',
'16,777,216 1',
'456,789,100,000,000',
'456,789,100,000,000 M 2',
'456,789,100,000,000 B 5',
'456,789,100,000.000e+00 M 0',
'+16777216 B',
'1.2e101 G',
"{run('df', '/', :out).out.slurp.words[10] * 1024} B 2", # Linux df returns Kilobytes by default
'347,344 M -2', # round to -2 past the decimal
'1122334455 Q', # bad unit type example
;
 
printf "%33s : %s\n", $_, sufficate(|.words) for @tests;</lang>
{{out}}
<pre> 87,654,321 : 87.654321M
-998,877,665,544,332,211,000 3 : -998.878E
+112,233 0 : 112K
16,777,216 1 : 16.8M
456,789,100,000,000 : 456.7891T
456,789,100,000,000 M 2 : 456.79T
456,789,100,000,000 B 5 : 415.44727Ti
456,789,100,000.000e+00 M 0 : 457G
+16777216 B : 16Mi
1.2e101 G : 12googol
703674818560 B 2 : 655.35Gi
347,344 M -2 : 300K
1122334455 Q : What we have here is a failure to communicate...</pre>
 
=={{header|REXX}}==
Line 958 ⟶ 1,023:
specified radix =
new number = 12googol</pre>
 
=={{header|zkl}}==
{{libheader|GMP}} GNU Multiple Precision Arithmetic Library (big ints)
Line 1,047 ⟶ 1,113:
1122334455 , 666 : Invalid suffix
10 : 10
</pre>
 
=={{header|Python}}==
{{works with|cpython|3.7.3}}
Tested in Python 3.7.3<br />
Chose 3 places after decimal (where applicable) as default rounding precision. Number to suffize taken as a string. There are some edge cases where this fails due to binary arithmetic differing from decimal arithmetic and things not rounding nicely.
<lang python>
import math
import os
 
 
def suffize(num, digits=None, base=10):
suffixes = ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 'X', 'W', 'V', 'U', 'googol']
 
exponent_distance = 10 if base == 2 else 3
num = num.strip().replace(',', '')
num_sign = num[0] if num[0] in '+-' else ''
 
num = abs(float(num))
 
if base == 10 and num >= 1e100:
suffix_index = 13
num /= 1e100
elif num > 1:
magnitude = math.floor(math.log(num, base))
suffix_index = min(math.floor(magnitude / exponent_distance), 12)
num /= base ** (exponent_distance * suffix_index)
else:
suffix_index = 0
 
if digits is not None:
num_str = f'{num:.{digits}f}'
else:
num_str = f'{num:.3f}'.strip('0').strip('.')
 
return num_sign + num_str + suffixes[suffix_index] + ('i' if base == 2 else '')
 
 
tests = [('87,654,321',),
('-998,877,665,544,332,211,000', 3),
('+112,233', 0),
('16,777,216', 1),
('456,789,100,000,000', 2),
('456,789,100,000,000', 2, 10),
('456,789,100,000,000', 5, 2),
('456,789,100,000.000e+00', 0, 10),
('+16777216', None, 2),
('1.2e101',)]
 
for test in tests:
print(' '.join(str(i) for i in test) + ' : ' + suffize(*test))
</lang>
 
{{out}}
<pre>
87,654,321 : 87.654M
-998,877,665,544,332,211,000 3 : -998.878E
+112,233 0 : +112K
16,777,216 1 : 16.8M
456,789,100,000,000 2 : 456.79T
456,789,100,000,000 2 10 : 456.79T
456,789,100,000,000 5 2 : 415.44727Ti
456,789,100,000.000e+00 0 10 : 457G
+16777216 None 2 : +16Mi
1.2e101 : 12googol
</pre>
10,339

edits

Cookies help us deliver our services. By using our services, you agree to our use of cookies.