14
$\begingroup$

Is there a function that automatically adds the appropriate prefix to a Quantity object?

For example, I would like a function

quantityWithAppropriatePrefix[Quantity[0.000001,"Meter"]]

that would yield

Quantity[1,"Micrometers"]

For some units this hack works:

UnitConvert[UnitConvert[0.00001,"Meter"],"Imperial"],"SI"]
Quantity[10., "Micrometers"]
$\endgroup$
8
$\begingroup$

EDITED to include Mr.Wizard's replacement for Switch EDITED to cover additional cases

Roll your own:

quantityWithAppropriatePrefix[quant_Quantity] := 
  Fold[UnitConvert[#1, #2] &, quant,
   {"Imperial", "SI"}];

EDIT: As Kuba pointed out in a comment, this can be written more compactly as

quantityWithAppropriatePrefix[quant_Quantity] := 
  Fold[UnitConvert, quant, {"Imperial", "SI"}];

quantityWithAppropriatePrefix /@
 {Quantity[0.0000011, "Meter"],
  Quantity[0.0000033, "Feet"]}

{Quantity[1.1, "Micrometers"], Quantity[1.00584, "Micrometers"]}

A brute force approach:

quantityWithAppropriatePrefix[quant_Quantity] :=
 Module[{si = UnitConvert[quant, "SI"], mag,
   log10Mag, multiplier},
  mag = QuantityMagnitude[si];
  log10Mag = Round[Log10[mag], 3];
  multiplier = {"Yocto", "Zepto", "Atto", "Femto",
     "Pico", "Nano", "Micro", "Milli", "", "kilo",
     "Mega", "Giga", "Tera", "Peta", "Exa", "Zetta",
     "Yatta"}[[log10Mag/3 + 9]];
  Quantity[mag 10^-log10Mag, multiplier <> QuantityUnit[si]]];

  quantityWithAppropriatePrefix /@ {Quantity[0.0000011, "Meter"], 
      Quantity[0.0000033, "Feet"]}

{Quantity[1.1, "Micrometers"], Quantity[1.00584, "Micrometers"]}

Partition[Table[quantityWithAppropriatePrefix[
    Quantity[1.23*10^n, "Volt"]], {n, -25, 25}],
  6] // Grid

enter image description here

| improve this answer | |
$\endgroup$
  • $\begingroup$ You didn't leave a lot of room for improvement but I'll try anyway. If this is used a lot Switch is not the best choice as it is slower than other options such as a Dispatch table or Association, or a simple list extraction using Part. May I edit your answer or shall I post it as my own? $\endgroup$ – Mr.Wizard Aug 22 '14 at 1:02
  • $\begingroup$ @Mr.Wizard - Fell free to post your solution. $\endgroup$ – Bob Hanlon Aug 22 '14 at 1:05
  • 1
    $\begingroup$ I found that the difference in timing is completely swamped by other factors so it is not worth posting separately. My proposal is simply: multiplier = {"Yocto", "Zepto", "Atto", "Femto", "Pico", "Nano", "Micro", "Milli", "", "kilo", "Mega", "Giga", "Tera", "Peta", "Exa", "Zetta", "Yatta"}[[log10Mag/3 + 9]]. $\endgroup$ – Mr.Wizard Aug 22 '14 at 1:15
  • 1
    $\begingroup$ UnitConvert is enough, no need to UnitConvert[ #, #2]&. $\endgroup$ – Kuba May 11 '16 at 14:03
  • $\begingroup$ @Kuba - Thanks, included above. $\endgroup$ – Bob Hanlon May 11 '16 at 16:00
5
$\begingroup$

Just a variant:

qf[u_] := Module[{rng = Range[-24, 24, 3],
   multiplier = {"Yocto", "Zepto", "Atto", "Femto", "Pico", "Nano", 
     "Micro", "Milli", "", "Kilo", "Mega", "Giga", "Tera", "Peta", 
     "Exa", "Zetta", "Yatta"}, v, p}, 
  v = QuantityMagnitude[u];
  p = First@Nearest[rng, Log10[v]];
  Quantity[
   v 10^-p, (p /. Thread[rng -> multiplier]) <> QuantityUnit[u]]
  ]
| improve this answer | |
$\endgroup$
2
$\begingroup$

This is a brute force solution, but seems to be more robust and does not require an internet connection, that I put together based on the other posts in this thread.

AutoSIPrefix[quant_Quantity] := (Module[
    {prefixlist, prefixrules, siunitstring, pfloc, baseunit, 
     basequantity, mag, log10Mag, prefix, newunit},
    prefixlist = 
     "kilo" | "mega" | "giga" | "tera" | "peta" | "exa" | "zetta" | 
      "yotta" | "deci" | "centi" | "milli" | "micro" | "nano" | 
      "pico" | "femto" | "atto" | "zepto" | "yocto";
    prefixrules = {3 -> "Kilo", 6 -> "Mega", 9 -> "Giga", 
      12 -> "Tera", 15 -> "Peta", 18 -> "Exa", 21 -> "Zetta", 
      24 -> "Yotta", -1 -> "Deci", -2 -> "Centi", -3 -> "Milli", -6 ->
        "Micro", -9 -> "Nano", -12 -> "Pico", -15 -> 
       "Femto" - 18 -> "Atto", -21 -> "Zepto", -24 -> "Yocto", 
      0 -> ""};
    siunitstring = QuantityUnit[UnitConvert[quant, "SI"]];
    pfloc = 
     StringPosition[siunitstring, prefixlist, IgnoreCase -> True];
    baseunit = 
     If[Length[pfloc] == 1, 
      Capitalize[StringDrop[siunitstring, pfloc[[1]]]], 
      Capitalize[siunitstring]];
    basequantity = 
     UnitConvert[quant, 
      Capitalize[StringDrop[siunitstring, pfloc[[1]]]]];
    mag = QuantityMagnitude[basequantity];
    log10Mag = Round[Log10[mag], 3];
    prefix = log10Mag /. prefixrules;
    newunit = Capitalize[ prefix <> ToLowerCase[baseunit]];
    UnitConvert[quant, newunit]]);
| improve this answer | |
$\endgroup$
0
$\begingroup$

The answer by @ubpdqn, with some small modifications to accept units with prefixes and avoid magnitudes smaller than 1.

NicePrefix[input_Quantity] := Module[
  {
   rng = Range[-24, 24, 3], 
   multiplier = {"Yocto", "Zepto", "Atto", "Femto", "Pico", "Nano", 
     "Micro", "Milli", "", "Kilo", "Mega", "Giga", "Tera", "Peta", 
     "Exa", "Zetta", "Yatta"},
   value, power, baseunit
   },
  baseunit = StringDelete[QuantityUnit[input], multiplier];
  value = QuantityMagnitude[input, Capitalize@baseunit];
  power = Clip[Floor[Log10[value], 3], {-24, 24}];
  Quantity[
   value Power[10, -power], (power /. Thread[rng -> multiplier]) <> baseunit]
  ]
| improve this answer | |
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.