# Convert between SI prefixes

## Introduction

The International System of Units is a system of measuring all around the world, except for a few countries including the US. The SI system (or metric system) is based on powers of ten, listed below (note that this is an incomplete table):

femto(f) pico(p) nano(n) micro(μ) milli(m) centi(c) (base unit) hecto(h) kilo(k) mega(M) giga(G) tera(T) peta(P)
10^-15   10^-12  10^-9   10^-6    10^-3    10^-2    10^0        10^2     10^3    10^6    10^9    10^12   10^15


Your job will to be to take in one of these measures and convert it into another.

Input will be a decimal number 10^-16 < x < 2^31 - 1, an SI prefix, a letter representing a quantity, another SI prefix to convert to, and the same quantity letter. Input will be in the format 1234.56 mC to TC, and will always match with the regex ^\d+(\.\d+)? [fpnμmchkMGTP](?'letter'[a-zA-Z]) to [fpnμmchkMGTP](?P=letter)$. You will never have to convert to/from the base unit (10^0) ## Output Output will be the same number as the input, just converted to a new SI prefix. Specifically, the program should convert the number from SI prefix 1 to SI prefix 2 in the input. Examples: Input: 1 nm to μm Output: 0.001 Input: 82 kC to cC Output: 8200000 Input: 6.54 MK to hK Output: 65400 Input: 2000 MB to GB Output: 2  This is , so shortest code in bytes wins! • Another thing, when generating a large/small number in this way, what should the output be? e.g. 1 PB to fB Dec 3, 2015 at 15:31 • @FryAmTheEggman you may assume the input will never produce an output that is larger/smaller than the range of digits that your language can natively handle (I think that is what you are asking). Dec 3, 2015 at 17:06 • Should we use U+00B5 MICRO SIGN or U+03BC GREEK SMALL LETTER MU? Can we choose either one or do we have to support one or both? Dec 3, 2015 at 17:06 • @Pietu1998 either one is fine. Dec 3, 2015 at 17:12 • Are we allowed to output a floating point number even if the result is an integer? Dec 3, 2015 at 17:27 ## 7 Answers # JavaScript (ES7), 113 109 bytes s=>(p=s.split )[m={f:-9,p:-6,n:-3,µ:0,m:3,c:4,h:8,k:9,M:12,G:15,T:18,P:21},0]/(10**(m[p[3][0]]-m[p[1][0]]))  Edit: Apparently we can use µ(U+00B5 MICRO SIGN) for the micro sign now, so replacing with that saves a byte. For ES6 compatibility (10**(m[p[3][0]]-m[p[1][0]])) can be replaced with Math.pow(10,m[p[3][0]]-m[p[1][0]]) for 114 bytes. ## Explanation s=> // s = input string (p=s.split ) // p = input parts // m = dictionary of SI prefix digit powers of 10 // the exact values don't matter as long as they are relative to each other [m={f:-9,p:-6,n:-3,µ:0,m:3,c:4,h:8,k:9,M:12,G:15,T:18,P:21}, 0] // get the number /(10**(m[p[3][0]]-m[p[1][0]])) // get the factor to divide by from the difference // between the SI prefix powers of 10  ## Test This test uses Math.pow instead of ** so that common browsers can test it. <input type="text" id="input" value="2000 MB to GB" /><button onclick="result.innerHTML=( s=>(p=s.split )[m={f:-9,p:-6,n:-3,µ:0,m:3,c:4,h:8,k:9,M:12,G:15,T:18,P:21},0]/Math.pow(10,m[p[3][0]]-m[p[1][0]]) )(input.value)">Go</button><pre id="result"></pre> # Haskell, 143 bytes Call s. import Data.List s=i.words i(n:f:_:[t])=read n*10**(x f-x t) x=j.flip elemIndex"f p n µ mc hk M G T P".head j(Just n)=fromIntegral n  • I like your "f p n µ mc hk M G T P" trick a lot. +1 – Lynn Dec 3, 2015 at 21:43 • I like this trick also. A tip: you can combine x and j with a pattern guard to: x y|Just n<-elemIndex(y!!0)"f p n µ mc hk M G T P"=fromIntegral n. – nimi Dec 3, 2015 at 21:48 # CJam, 67 bytes lS%:I0=dA"fpnµmchkMGTP"[-7 -4WY5 6ABEHK23]+:AAI3=c#C+=AAI1=c#C+=-#/  Try it online! Uses µ (U+00B5) for the micro sign so make sure you use this in your input instead of the μ (U+03BC) in the question. My first attempt at using CJam. Feel free to suggest improvements because I'm sure there are many! ## Explanation Same method as my JavaScript answer. lS%:P e# P = input parts separated by space 0=d e# get number as double A "fpnµmchkMGTP" [-7 -4WY5 6ABEHK23]+ :A e# A = array of SI prefixes followed by their (relative) values AP3=c e# desired SI prefix #C+= e# get SI value of prefix AAP1=c e# current SI prefix #C+=- e# subtract value of prefix # e# get power of SI prefix difference / e# divide value by 10 ^ SI prefix difference  # Ruby (2.2.1), 126 123 bytes r={f:-9,p:-6,n:-3,µ:0,m:3,c:4,h:8,k:9,M:12,G:15,T:18,P:21};p ($*[0].to_r/10**(r[$*[3][0].to_sym]-r[$*[1][0].to_sym])).to_f


Saved 3 bytes thanks to user81655

## Explanation

# Hash of prefixes to relative powers
r={f:-9,p:-6,n:-3,µ:0,m:3,c:4,h:8,k:9,M:12,G:15,T:18,P:21};
p (                      # print (inspect)
$*[0].to_r # input value / 10 ** ( # divided by 10^... r[$*[3][0].to_sym]   # first prefix symbol
-
r[$*[1][0].to_sym] # second prefix symbol ) ).to_f # convert to float for proper format on output  Takes input from the command line e.g ruby si.rb 1 nm to μm This is my first golf! • You can save 3 bytes if you use the values {f:-9,p:-6,n:-3,µ:0,m:3,c:4,h:8,k:9,M:12,G:15,T:18,P:21} for the hash table. Also replacing μ with µ (U+00B5) is allowed and will save another byte. Dec 3, 2015 at 20:11 • @user81655 good advice, thanks! The two mu/micro symbols seem to give the same byte count when I wc -c my file, any idea why that is? Dec 4, 2015 at 8:47 • No problem. Your file is probably encoded using something like UTF-8 which splits characters above 127 into two bytes. If you switch to a one-byte encoding like ANSI it should remove the extra byte from the file. Dec 4, 2015 at 9:17 # Pyth, 46 44 bytes The program assumes that the character µ (U+00B5 MICRO SIGN) is used for the micro sign. On Windows, this is what you get by pressing Alt Gr + M. The source code contains some unprintables, so here is a reversible xxd hex dump. 0000000: 2a76 684a 637a 645e 542d 466d 406a 4322 *vhJczd^T-Fm@jC" 0000010: 5c72 575d d623 8b9e 53bb 4c09 b275 2233 \rW].#..S.L..u"3 0000020: 3125 7443 6864 3137 2532 744a 1%tChd17%2tJ  Here's a copy-friendly version: *vhJczd^T-Fm@j1057004749883241517573776978549 31%tChd17%2tJ  You can try the demo or use the test suite. If these links fail, use the copy-friendly version (demo, test suite). # Haskell, 121 bytes (e:l:i)!d|e==d=fromEnum l|0<1=i!d b#i="fpcnfµimlcmhqkrMuGxT{P~"!(b!!i) g[(a,b)]=10**fromIntegral(b#1-b#7)*read a f=g.lex  Defines a function f :: String -> Double. For example: *Main> f "6.54 MK to hK" 65400.0  # Perl 5, 113 + 8 (-p -Mutf8) = 121 bytes %c=(f,-15,p,-12,n,-9,µ,-6,'m',-3,c,-2,h,2,k,3,M,6,G,9,T,12,P,15);/([0-9.]+) (.).*(.)./;$_=$1*10**($c{$2}-$c{\$3})
`

Try it online!