Convert Numbers to Si Prefix

Convert numbers to SI prefix


require(sitools)
f2si(80000)
[1] "80 k"
f2si(8E12)
[1] "8 T"

It seems to be very simplistic as it appends two spaces if no SI prefix is used:

f2si(80)
[1] "80 "

The function is easy to modify to include rounding. I also fixed the issue with appended spaces.

f2si2<-function (number,rounding=F) 
{
lut <- c(1e-24, 1e-21, 1e-18, 1e-15, 1e-12, 1e-09, 1e-06,
0.001, 1, 1000, 1e+06, 1e+09, 1e+12, 1e+15, 1e+18, 1e+21,
1e+24)
pre <- c("y", "z", "a", "f", "p", "n", "u", "m", "", "k",
"M", "G", "T", "P", "E", "Z", "Y")
ix <- findInterval(number, lut)
if (lut[ix]!=1) {
if (rounding==T) {
sistring <- paste(round(number/lut[ix]), pre[ix])
}
else {
sistring <- paste(number/lut[ix], pre[ix])
}
}
else {
sistring <- as.character(number)
}
return(sistring)
}

f2si2(12345)
[1] "12.345 k"
f2si2(12345,T)
[1] "12 k"

SI-prefixes for number format in MS Excel

No solution will work better than scientific notation.

If you use custom number formats, then you would have to enter them manually (or with VBA) such that they will mask the actual content of the cell.

For instance, if you want to display the following format pairs:

1 n  1E-09
1 µ 1E-06
1 m 1E-03
1 1
1 k 1E+03
1 M 1E+06
1 G 1E+09

If you have 0.001, you would have to set the format as "1 m" -- this will mask the number, so if you have 0.002 you would have to set it as "2 m" -- if you changed it to 0.004 it would still display 2 m as a result. This obviously isn't ideal.

You could set it up as a two-column sheet, where you have the values in the left, and use a formula to display with units on the right, but then you end up not being able to do math with the formatted values.

So basically, the answer is "no", it isn't possible.

You could theoretically write a VBA script that will automatically change the visible contents according to the cell contents whenever a number is changed, but the script would be bulky and would cause serious trouble to whoever you sent to if they had macros off. It would also require all sorts of corner cases depending on if you wanted numbers formatted 'normally' in certain cells. So while it may be theoretically possible, it is practically impossible

Formatting a number with a metric prefix (SI style)

You can use a dictionary of prefices:

prefix = {"y":1e-24, "z":1e-21, "a":1e-18, "f":1e-15, "p": 1e-12,
"n":1e-9, "u":1e-6, "µ":1e-6, "m":1e-3, "c":1e-2, "d":0.1,
"h":100, "k":1000, "M":1e6, "G":1e9, "T":1e12, "P":1e15,
"E":1e18, "Z":1e21, "Y":1e24}

def meter(s):
try:
# multiply with meter-prefix value
return float(s[:-1])*prefix[s[-1]]
except KeyError:
# no or unknown meter-prefix
return float(s)


for a in ["1u", "2m", "1.1u", "42", "6k"]:
print(meter(a))

Result:

1e-06
0.002
1.1e-06
42.0
6000.0

Format a number with SI Prefix, with fixed number of decimals

You almost got it right. Using d3.formatPrefix() one can get the SI prefix. To get the rounded number without decimals, I used Javascript's .toFixed():

var prefix = d3.formatPrefix(137594020);
console.log(prefix.symbol); // "M"
console.log(prefix.scale(137594020).toFixed()); // 138

var prefix = d3.formatPrefix(13759402);
console.log(prefix.symbol); // "M"
console.log(prefix.scale(13759402).toFixed()); // 14

var prefix = d3.formatPrefix(1375);
console.log(prefix.symbol); // "k"
console.log(prefix.scale(1375).toFixed()); // 1

You can try it yourself at jsfiddle.

Convert float number to string with engineering notation (with SI prefix) in Python

Here is a function inspired from Formatting a number with a metric prefix?

metric.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import math


def to_si(d, sep=' '):
"""
Convert number to string with SI prefix

:Example:

>>> to_si(2500.0)
'2.5 k'

>>> to_si(2.3E6)
'2.3 M'

>>> to_si(2.3E-6)
'2.3 µ'

>>> to_si(-2500.0)
'-2.5 k'

>>> to_si(0)
'0'

"""

inc_prefixes = ['k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']
dec_prefixes = ['m', 'µ', 'n', 'p', 'f', 'a', 'z', 'y']

if d == 0:
return str(0)

degree = int(math.floor(math.log10(math.fabs(d)) / 3))

prefix = ''

if degree != 0:
ds = degree / math.fabs(degree)
if ds == 1:
if degree - 1 < len(inc_prefixes):
prefix = inc_prefixes[degree - 1]
else:
prefix = inc_prefixes[-1]
degree = len(inc_prefixes)

elif ds == -1:
if -degree - 1 < len(dec_prefixes):
prefix = dec_prefixes[-degree - 1]
else:
prefix = dec_prefixes[-1]
degree = -len(dec_prefixes)

scaled = float(d * math.pow(1000, -degree))

s = "{scaled}{sep}{prefix}".format(scaled=scaled,
sep=sep,
prefix=prefix)

else:
s = "{d}".format(d=d)

return s


if __name__ == "__main__":
import doctest
doctest.testmod()

and its usage:

from metric import to_si
d = 23392342.1
print(to_si(d))

It will display

23.3923421 M

How to round off to 2 decimal places with format SI prefix?

All you need is d3.formatPrefix, which...

Convert values to the units of the appropriate SI prefix for the specified numeric reference value before formatting in fixed point notation.

..., with ".2" as the specifier and your own number as the value.

Here is the demo with your number:





const myNumber = 656628;

console.log(d3.formatPrefix(".2", myNumber)(myNumber));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

Formatting a number with a metric prefix?

Try this out. I haven't tested it, but it should be more or less correct.

public string ToSI(double d, string format = null)
{
char[] incPrefixes = new[] { 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y' };
char[] decPrefixes = new[] { 'm', '\u03bc', 'n', 'p', 'f', 'a', 'z', 'y' };

int degree = (int)Math.Floor(Math.Log10(Math.Abs(d)) / 3);
double scaled = d * Math.Pow(1000, -degree);

char? prefix = null;
switch (Math.Sign(degree))
{
case 1: prefix = incPrefixes[degree - 1]; break;
case -1: prefix = decPrefixes[-degree - 1]; break;
}

return scaled.ToString(format) + prefix;
}

Convert string with engineer prefix to float

Try this out, no regex needed:

pos_postfixes = ['k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']
neg_postfixes = ['m', 'µ', 'n', 'p', 'f', 'a', 'z', 'y']

num_postfix = n[-1]
if num_postfix in pos_postfixes:
num = float(n[:-1])
num*=10**((pos_postfixes.index(num_postfix)+1)*3)
elif num_postfix in neg_postfixes:
num = float(n[:-1])
num*=10**(-(neg_postfixes.index(num_postfix)+1)*3)
else:
num = float(n)
print(num)

Another thing to note is that in python, it is more common to use underscore variable names than camelcasing, see the pep-8: http://www.python.org/dev/peps/pep-0008/



Related Topics



Leave a reply



Submit