use fastnum::{dec128 as d, D128, D256};
use crate::Number;
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum UnitType {
NoType,
Time,
Length,
Area,
Volume,
Mass,
DigitalStorage,
DataTransferRate,
Energy,
Power,
ElectricCurrent,
Resistance,
Voltage,
Pressure,
Frequency,
Speed,
Temperature,
}
use UnitType::*;
macro_rules! create_units {
( $( $variant:ident : $properties:expr ),*, ) => {
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum Unit {
$($variant),*
}
use Unit::*;
impl Unit {
pub fn category(&self) -> UnitType {
match self {
$(
Unit::$variant => $properties.0
),*
}
}
pub fn weight(&self) -> D128 {
match self {
$(
Unit::$variant => $properties.1
),*
}
}
pub(crate) fn singular(&self) -> &str {
match self {
$(
Unit::$variant => $properties.2
),*
}
}
pub(crate) fn plural(&self) -> &str {
match self {
$(
Unit::$variant => $properties.3
),*
}
}
}
}
}
create_units!(
NoUnit: (NoType, d!(1), "", ""),
Nanosecond: (Time, d!(1), "nanosecond", "nanoseconds"),
Microsecond: (Time, d!(1000), "microsecond", "microseconds"),
Millisecond: (Time, d!(1000000), "millisecond", "milliseconds"),
Second: (Time, d!(1000000000), "second", "seconds"),
Minute: (Time, d!(60000000000), "minute", "minutes"),
Hour: (Time, d!(3600000000000), "hour", "hours"),
Day: (Time, d!(86400000000000), "day", "days"),
Week: (Time, d!(604800000000000), "week", "weeks"),
Month: (Time, d!(2629746000000000), "month", "months"),
Quarter: (Time, d!(7889238000000000), "quarter", "quarters"),
Year: (Time, d!(31556952000000000), "year", "years"),
Decade: (Time, d!(315569520000000000), "decade", "decades"),
Century: (Time, d!(3155695200000000000), "century", "centuries"),
Millenium: (Time, d!(31556952000000000000), "millenium", "millenia"),
Millimeter: (Length, d!(1), "millimeter", "millimeters"),
Centimeter: (Length, d!(10), "centimeter", "centimeters"),
Decimeter: (Length, d!(100), "decimeter", "decimeters"),
Meter: (Length, d!(1000), "meter", "meters"),
Kilometer: (Length, d!(1000000), "kilometer", "kilometers"),
Inch: (Length, d!(25.4), "inch", "inches"),
Foot: (Length, d!(304.8), "foot", "feet"),
Yard: (Length, d!(914.4), "yard", "yards"),
Mile: (Length, d!(1609344), "mile", "miles"),
Marathon: (Length, d!(42195000), "marathon", "marathons"),
NauticalMile: (Length, d!(1852000), "nautical mile", "nautical miles"),
LightYear: (Length, d!(9460730472580800000), "light year", "light years"),
LightSecond: (Length, d!(299792458000), "light second", "light seconds"),
SquareMillimeter: (Area, d!(1), "square millimeter", "square millimeters"),
SquareCentimeter: (Area, d!(100), "square centimeter", "square centimeters"),
SquareDecimeter: (Area, d!(10000), "square decimeter", "square decimeters"),
SquareMeter: (Area, d!(1000000), "square meter", "square meters"),
SquareKilometer: (Area, d!(1000000000000), "square kilometer", "square kilometers"),
SquareInch: (Area, d!(645.16), "square inch", "square inches"),
SquareFoot: (Area, d!(92903.04), "square foot", "square feet"),
SquareYard: (Area, d!(836127.36), "square yard", "square yards"),
SquareMile: (Area, d!(2589988110336.00), "square mile", "square miles"),
Are: (Area, d!(100000000), "are", "ares"),
Decare: (Area, d!(1000000000), "decare", "decare"),
Hectare: (Area, d!(10000000000), "hectare", "hectares"),
Acre: (Area, d!(4046856422.40), "acre", "acres"),
CubicMillimeter: (Volume, d!(1), "cubic millimeter", "cubic millimeters"),
CubicCentimeter: (Volume, d!(1000), "cubic centimeter", "cubic centimeters"),
CubicDecimeter: (Volume, d!(1000000), "cubic decimeter", "cubic decimeters"),
CubicMeter: (Volume, d!(1000000000), "cubic meter", "cubic meters"),
CubicKilometer: (Volume, d!(1000000000000000000), "cubic kilometer", "cubic kilometers"),
CubicInch: (Volume, d!(16387.064), "cubic inch", "cubic inches"),
CubicFoot: (Volume, d!(28316846.592), "cubic foot", "cubic feet"),
CubicYard: (Volume, d!(764554857.984), "cubic yard", "cubic yards"),
CubicMile: (Volume, d!(4168181825440579584), "cubic mile", "cubic miles"),
Milliliter: (Volume, d!(1000), "milliliter", "milliliters"),
Centiliter: (Volume, d!(10000), "centiliter", "centiliters"),
Deciliter: (Volume, d!(100000), "deciliter", "deciliters"),
Liter: (Volume, d!(1000000), "liter", "liters"),
Teaspoon: (Volume, d!(4928.92159375), "teaspoon", "teaspoons"),
Tablespoon: (Volume, d!(14786.76478125), "tablespoon", "tablespoons"),
FluidOunce: (Volume, d!(29573.5295625), "fluid ounce", "fluid ounces"),
Cup: (Volume, d!(236588.2365), "cup", "cups"),
Pint: (Volume, d!(473176.473), "pint", "pints"),
Quart: (Volume, d!(946352.946), "quart", "quarts"),
Gallon: (Volume, d!(3785411.784), "gallon", "gallons"),
OilBarrel: (Volume, d!(158987294.928), "oil barrel", "oil barrels"),
Milligram: (Mass, d!(0.001), "milligram", "milligrams"),
Gram: (Mass, d!(1), "gram", "grams"),
Hectogram: (Mass, d!(100), "hectogram", "hectograms"),
Kilogram: (Mass, d!(1000), "kilogram", "kilograms"),
MetricTon: (Mass, d!(1000000), "metric ton", "metric tons"),
Ounce: (Mass, d!(28.349523125), "ounce", "ounces"),
Pound: (Mass, d!(453.59237), "pound", "pounds"),
Stone: (Mass, d!(6350.29318), "stone", "stones"),
ShortTon: (Mass, d!(907184.74), "short ton", "short tons"),
LongTon: (Mass, d!(1016046.9088), "long ton", "long tons"),
Bit: (DigitalStorage, d!(1), "bit", "bits"),
Kilobit: (DigitalStorage, d!(1000), "kilobit", "kilobits"),
Megabit: (DigitalStorage, d!(1000000), "megabit", "megabits"),
Gigabit: (DigitalStorage, d!(1000000000), "gigabit", "gigabits"),
Terabit: (DigitalStorage, d!(1000000000000), "terabit", "terabits"),
Petabit: (DigitalStorage, d!(1000000000000000), "petabit", "petabits"),
Exabit: (DigitalStorage, d!(1000000000000000000), "exabit", "exabits"),
Zettabit: (DigitalStorage, d!(1000000000000000000000), "zettabit", "zettabits"),
Yottabit: (DigitalStorage, d!(1000000000000000000000000), "yottabit", "yottabits"),
Kibibit: (DigitalStorage, d!(1024), "kibibit", "kibibits"),
Mebibit: (DigitalStorage, d!(1048576), "mebibit", "mebibits"),
Gibibit: (DigitalStorage, d!(1073741824), "gibibit", "gibibits"),
Tebibit: (DigitalStorage, d!(1099511627776), "tebibit", "tebibits"),
Pebibit: (DigitalStorage, d!(1125899906842624), "pebibit", "pebibits"),
Exbibit: (DigitalStorage, d!(1152921504606846976), "exbibit", "exbibits"),
Zebibit: (DigitalStorage, d!(1180591620717411303424), "zebibit", "zebibits"),
Yobibit: (DigitalStorage, d!(1208925819614629174706176), "yobibit", "yobibits"),
Byte: (DigitalStorage, d!(8), "byte", "bytes"),
Kilobyte: (DigitalStorage, d!(8000), "kilobyte", "kilobytes"),
Megabyte: (DigitalStorage, d!(8000000), "megabyte", "megabytes"),
Gigabyte: (DigitalStorage, d!(8000000000), "gigabyte", "gigabytes"),
Terabyte: (DigitalStorage, d!(8000000000000), "terabyte", "terabytes"),
Petabyte: (DigitalStorage, d!(8000000000000000), "petabyte", "petabytes"),
Exabyte: (DigitalStorage, d!(8000000000000000000), "exabyte", "exabytes"),
Zettabyte: (DigitalStorage, d!(8000000000000000000000), "zettabyte", "zettabytes"),
Yottabyte: (DigitalStorage, d!(8000000000000000000000000), "yottabyte", "yottabytes"),
Kibibyte: (DigitalStorage, d!(8192), "kibibyte", "kibibytes"),
Mebibyte: (DigitalStorage, d!(8388608), "mebibyte", "mebibytes"),
Gibibyte: (DigitalStorage, d!(8589934592), "gibibyte", "gibibytes"),
Tebibyte: (DigitalStorage, d!(8796093022208), "tebibyte", "tebibytes"),
Pebibyte: (DigitalStorage, d!(9007199254740992), "pebibyte", "pebibytes"),
Exbibyte: (DigitalStorage, d!(9223372036854775808), "exbibyte", "exbibytes"),
Zebibyte: (DigitalStorage, d!(9444732965739290427392), "zebibyte", "zebibytes"),
Yobibyte: (DigitalStorage, d!(9671406556917033397649408), "yobibyte", "yobibytes"),
BitsPerSecond: (DataTransferRate, d!(1), "bit per second", "bits per second"),
KilobitsPerSecond: (DataTransferRate, d!(1000), "kilobit per second", "kilobits per second"),
MegabitsPerSecond: (DataTransferRate, d!(1000000), "megabit per second", "megabits per second"),
GigabitsPerSecond: (DataTransferRate, d!(1000000000), "gigabit per second", "gigabits per second"),
TerabitsPerSecond: (DataTransferRate, d!(1000000000000), "terabit per second", "terabits per second"),
PetabitsPerSecond: (DataTransferRate, d!(1000000000000000), "petabit per second", "petabits per second"),
ExabitsPerSecond: (DataTransferRate, d!(1000000000000000000), "exabit per second", "exabits per second"),
ZettabitsPerSecond: (DataTransferRate, d!(1000000000000000000000), "zettabit per second", "zettabits per second"),
YottabitsPerSecond: (DataTransferRate, d!(1000000000000000000000000), "yottabit per second", "yottabits per second"),
KibibitsPerSecond: (DataTransferRate, d!(1024), "kibibit per second", "kibibits per second"),
MebibitsPerSecond: (DataTransferRate, d!(1048576), "mebibit per second", "mebibits per second"),
GibibitsPerSecond: (DataTransferRate, d!(1073741824), "gibibit per second", "gibibits per second"),
TebibitsPerSecond: (DataTransferRate, d!(1099511627776), "tebibit per second", "tebibits per second"),
PebibitsPerSecond: (DataTransferRate, d!(1125899906842624), "pebibit per second", "pebibits per second"),
ExbibitsPerSecond: (DataTransferRate, d!(1152921504606846976), "exbibit per second", "exbibits per second"),
ZebibitsPerSecond: (DataTransferRate, d!(1180591620717411303424), "zebibit per second", "zebibits per second"),
YobibitsPerSecond: (DataTransferRate, d!(1208925819614629174706176), "yobibit per second", "yobibits per second"),
BytesPerSecond: (DataTransferRate, d!(8), "byte per second", "bytes per second"),
KilobytesPerSecond: (DataTransferRate, d!(8000), "kilobyte per second", "kilobytes per second"),
MegabytesPerSecond: (DataTransferRate, d!(8000000), "megabyte per second", "megabytes per second"),
GigabytesPerSecond: (DataTransferRate, d!(8000000000), "gigabyte per second", "gigabytes per second"),
TerabytesPerSecond: (DataTransferRate, d!(8000000000000), "terabyte per second", "terabytes per second"),
PetabytesPerSecond: (DataTransferRate, d!(8000000000000000), "petabyte per second", "petabytes per second"),
ExabytesPerSecond: (DataTransferRate, d!(8000000000000000000), "exabyte per second", "exabytes per second"),
ZettabytesPerSecond: (DataTransferRate, d!(8000000000000000000000), "zettabyte per second", "zettabytes per second"),
YottabytesPerSecond: (DataTransferRate, d!(8000000000000000000000000), "yottabyte per second", "yottabytes per second"),
KibibytesPerSecond: (DataTransferRate, d!(8192), "kibibyte per second", "kibibytes per second"),
MebibytesPerSecond: (DataTransferRate, d!(8388608), "mebibyte per second", "mebibytes per second"),
GibibytesPerSecond: (DataTransferRate, d!(8589934592), "gibibyte per second", "gibibytes per second"),
TebibytesPerSecond: (DataTransferRate, d!(8796093022208), "tebibyte per second", "tebibytes per second"),
PebibytesPerSecond: (DataTransferRate, d!(9007199254740992), "pebibyte per second", "pebibytes per second"),
ExbibytesPerSecond: (DataTransferRate, d!(9223372036854775808), "exbibyte per second", "exbibytes per second"),
ZebibytesPerSecond: (DataTransferRate, d!(9444732965739290427392), "zebibyte per second", "zebibytes per second"),
YobibytesPerSecond: (DataTransferRate, d!(9671406556917033397649408), "yobibyte per second", "yobibytes per second"),
Millijoule: (Energy, d!(0.001), "millijoule", "millijoules"),
Joule: (Energy, d!(1), "joule", "joules"),
NewtonMeter: (Energy, d!(1), "newton meter", "newton meters"),
Kilojoule: (Energy, d!(1000), "kilojoule", "kilojoules"),
Megajoule: (Energy, d!(1000000), "megajoule", "megajoules"),
Gigajoule: (Energy, d!(1000000000), "gigajoule", "gigajoules"),
Terajoule: (Energy, d!(1000000000000), "terajoule", "terajoules"),
Calorie: (Energy, d!(4.1868), "calorie", "calories"),
KiloCalorie: (Energy, d!(4186.8), "kilocalorie", "kilocalories"),
BritishThermalUnit: (Energy, d!(1055.05585262), "British thermal unit", "British thermal units"),
WattHour: (Energy, d!(3600), "watt-hour", "watt-hours"),
KilowattHour: (Energy, d!(3600000), "kilowatt-hour", "kilowatt-hours"),
MegawattHour: (Energy, d!(3600000000), "megawatt-hour", "megawatt-hours"),
GigawattHour: (Energy, d!(3600000000000), "gigawatt-hour", "gigawatt-hours"),
TerawattHour: (Energy, d!(3600000000000000), "terawatt-hour", "terawatt-hours"),
PetawattHour: (Energy, d!(3600000000000000000), "petawatt-hour", "petawatt-hours"),
Milliwatt: (Power, d!(0.001), "milliwatt", "milliwatts"),
Watt: (Power, d!(1), "watt", "watts"),
Kilowatt: (Power, d!(1000), "kilowatt", "kilowatts"),
Megawatt: (Power, d!(1000000), "megawatt", "megawatts"),
Gigawatt: (Power, d!(1000000000), "gigawatt", "gigawatts"),
Terawatt: (Power, d!(1000000000000), "terawatt", "terawatts"),
Petawatt: (Power, d!(1000000000000000), "petawatt", "petawatts"),
BritishThermalUnitsPerMinute: (Power, d!(0.0568690272188), "british thermal unit per minute", "british thermal units per minute"),
BritishThermalUnitsPerHour: (Power, d!(3.412141633128), "british thermal unit per hour", "british thermal units per hour"),
Horsepower: (Power, d!(745.69987158227022), "horsepower", "horsepower"),
MetricHorsepower: (Power, d!(735.49875), "metric horsepower", "metric horsepower"),
Milliampere: (ElectricCurrent, d!(0.001), "milliampere", "milliamperes"),
Ampere: (ElectricCurrent, d!(1), "ampere", "amperes"),
Kiloampere: (ElectricCurrent, d!(1000), "kiloampere", "kiloamperes"),
Abampere: (ElectricCurrent, d!(10), "abampere", "abamperes"),
Milliohm: (Resistance, d!(0.001), "milliohm", "milliohms"),
Ohm: (Resistance, d!(1), "ohm", "ohms"),
Kiloohm: (Resistance, d!(1000), "kiloohm", "kiloohms"),
Millivolt: (Voltage, d!(0.001), "millivolt", "millivolts"),
Volt: (Voltage, d!(1), "volt", "volts"),
Kilovolt: (Voltage, d!(1000), "kilovolt", "kilovolts"),
Pascal: (Pressure, d!(1), "pascal", "pascals"),
Kilopascal: (Pressure, d!(1000), "kilopascal", "kilopascals"),
Atmosphere: (Pressure, d!(101325), "atmosphere", "atmospheres"),
Millibar: (Pressure, d!(100), "millibar", "millibars"),
Bar: (Pressure, d!(100000), "bar", "bars"),
InchOfMercury: (Pressure, d!(3386.389), "inch of mercury", "inches of mercury"),
PoundsPerSquareInch: (Pressure, d!(6894.757293168361), "pound per square inch", "pounds per square inch"),
Torr: (Pressure, d!(162.12), "torr", "torr"),
Hertz: (Frequency, d!(1), "hertz", "hertz"),
Kilohertz: (Frequency, d!(1000), "kilohertz", "kilohertz"),
Megahertz: (Frequency, d!(1000000), "megahertz", "megahertz"),
Gigahertz: (Frequency, d!(1000000000), "gigahertz", "gigahertz"),
Terahertz: (Frequency, d!(1000000000000), "terahertz", "terahertz"),
Petahertz: (Frequency, d!(1000000000000000), "petahertz", "petahertz"),
RevolutionsPerMinute: (Frequency, d!(60), "revolution per minute", "revolutions per minute"),
KilometersPerHour: (Speed, d!(1), "kilometer per hour", "kilometers per hour"),
MetersPerSecond: (Speed, d!(3.6), "meter per second", "meters per second"),
MilesPerHour: (Speed, d!(1.609344), "mile per hour", "miles per hour"),
FeetPerSecond: (Speed, d!(1.09728), "foot per second", "feet per second"),
Knot: (Speed, d!(1.852), "knot", "knots"),
Kelvin: (Temperature, d!(0), "kelvin", "kelvin"),
Celsius: (Temperature, d!(0), "celsius", "celsius"),
Fahrenheit: (Temperature, d!(0), "fahrenheit", "fahrenheit"),
);
pub fn get_conversion_factor(unit: Unit, to_unit: Unit) -> D128 {
unit.weight() / to_unit.weight()
}
pub fn convert(number: Number, to_unit: Unit) -> Result<Number, String> {
if number.unit.category() != to_unit.category() {
return Err(format!("Cannot convert from {:?} to {:?}", number.unit, to_unit));
}
let value = number.value;
let ok = |new_value| {
Ok(Number::new(new_value, to_unit))
};
if number.unit.category() == UnitType::Temperature {
match (number.unit, to_unit) {
(Kelvin, Kelvin) => ok(value),
(Kelvin, Celsius) => ok(value-d!(273.15)),
(Kelvin, Fahrenheit) => ok(value*d!(1.8)-d!(459.67)),
(Celsius, Celsius) => ok(value),
(Celsius, Kelvin) => ok(value+d!(273.15)),
(Celsius, Fahrenheit) => ok(value*d!(1.8)+d!(32)),
(Fahrenheit, Fahrenheit) => ok(value),
(Fahrenheit, Kelvin) => ok((value+d!(459.67))*d!(5)/d!(9)),
(Fahrenheit, Celsius) => ok((value-d!(32))/d!(1.8)),
_ => Err(format!("Error converting temperature {:?} to {:?}", number.unit, to_unit)),
}
} else {
let conversion_factor = get_conversion_factor(number.unit, to_unit);
ok(number.value * conversion_factor)
}
}
pub fn convert_to_lowest(left: Number, right: Number) -> Result<(Number, Number), String> {
if left.unit.weight() == right.unit.weight() {
Ok((left, right))
} else if left.unit.weight() > right.unit.weight() {
let left_converted = convert(left, right.unit)?;
Ok((left_converted, right))
} else {
let right_converted = convert(right, left.unit)?;
Ok((left, right_converted))
}
}
pub fn add(left: Number, right: Number) -> Result<Number, String> {
if left.unit == right.unit {
Ok(Number::new(left.value + right.value, left.unit))
} else if left.unit.category() == right.unit.category() && left.unit.category() != Temperature {
let (left, right) = convert_to_lowest(left, right)?;
Ok(Number::new(left.value + right.value, left.unit))
} else {
Err(format!("Cannot add {:?} and {:?}", left.unit, right.unit))
}
}
pub fn subtract(left: Number, right: Number) -> Result<Number, String> {
if left.unit == right.unit {
Ok(Number::new(left.value - right.value, left.unit))
} else if left.unit.category() == right.unit.category() && left.unit.category() != Temperature {
let (left, right) = convert_to_lowest(left, right)?;
Ok(Number::new(left.value - right.value, left.unit))
} else {
Err(format!("Cannot subtract {:?} by {:?}", left.unit, right.unit))
}
}
pub fn to_ideal_unit(number: Number) -> Number {
let value = number.value * number.unit.weight();
if number.unit.category() == Length {
if value >= d!(1000000000000000000) { return Number::new(value/LightYear.weight(), LightYear)
} else if value >= d!(1000000) { return Number::new(value/Kilometer.weight(), Kilometer)
} else if value >= d!(1000) { return Number::new(value/Meter.weight(), Meter)
} else if value >= d!(10) { return Number::new(value/Centimeter.weight(), Centimeter)
} else {
return Number::new(value, Millimeter)
}
} else if number.unit.category() == Time {
if value >= d!(31556952000000000) {
return Number::new(value/Year.weight(), Year);
} else if value >= d!(86400000000000) {
return Number::new(value/Day.weight(), Day);
} else if value >= d!(3600000000000) {
return Number::new(value/Hour.weight(), Hour);
} else if value >= d!(60000000000) {
return Number::new(value/Minute.weight(), Minute);
} else if value >= d!(1000000000) {
return Number::new(value/Second.weight(), Second);
} else if value >= d!(1000000) {
return Number::new(value/Millisecond.weight(), Millisecond);
} else if value >= d!(1000) {
return Number::new(value/Microsecond.weight(), Microsecond);
} else {
return Number::new(value, Nanosecond);
}
} else if number.unit.category() == Area {
if value >= d!(1000000000000) { return Number::new(value/SquareKilometer.weight(), SquareKilometer)
} else if value >= d!(10000000000) { return Number::new(value/Hectare.weight(), Hectare)
} else if value >= d!(1000000) { return Number::new(value/SquareMeter.weight(), SquareMeter)
} else if value >= d!(100) { return Number::new(value/SquareCentimeter.weight(), SquareCentimeter)
} else {
return Number::new(value, SquareMillimeter)
}
} else if number.unit.category() == Volume {
if value >= d!(1000000000000000000) { return Number::new(value/CubicKilometer.weight(), CubicKilometer)
} else if value >= d!(1000000000) { return Number::new(value/CubicMeter.weight(), CubicMeter)
} else if value >= d!(1000000) { return Number::new(value/Liter.weight(), Liter)
} else if value >= d!(1000) { return Number::new(value/Milliliter.weight(), Milliliter)
} else {
return Number::new(value, CubicMillimeter)
}
} else if number.unit.category() == Energy {
if value >= d!(3600000000000000000) { return Number::new(value/PetawattHour.weight(), PetawattHour)
} else if value >= d!(3600000000000000) { return Number::new(value/TerawattHour.weight(), TerawattHour)
} else if value >= d!(3600000000000) { return Number::new(value/GigawattHour.weight(), GigawattHour)
} else if value >= d!(3600000000) { return Number::new(value/MegawattHour.weight(), MegawattHour)
} else if value >= d!(3600000) { return Number::new(value/KilowattHour.weight(), KilowattHour)
} else if value >= d!(3600) { return Number::new(value/WattHour.weight(), WattHour)
} else if value >= d!(1) { return Number::new(value, Joule)
} else {
return Number::new(value/Millijoule.weight(), Millijoule)
}
} else if number.unit.category() == Power {
if value >= d!(1000000000000000) { return Number::new(value/Petawatt.weight(), Petawatt)
} else if value >= d!(1000000000000) { return Number::new(value/Terawatt.weight(), Terawatt)
} else if value >= d!(1000000000) { return Number::new(value/Gigawatt.weight(), Gigawatt)
} else if value >= d!(1000000) { return Number::new(value/Megawatt.weight(), Megawatt)
} else if value >= d!(1000) { return Number::new(value/Kilowatt.weight(), Kilowatt)
} else if value >= d!(1) { return Number::new(value, Watt)
} else {
return Number::new(value/Milliwatt.weight(), Milliwatt)
}
} else if number.unit.category() == ElectricCurrent {
if value >= d!(1000) { return Number::new(value/Kiloampere.weight(), Kiloampere)
} else if value >= d!(1) { return Number::new(value, Ampere)
} else {
return Number::new(value/Milliampere.weight(), Milliampere)
}
} else if number.unit.category() == Resistance {
if value >= d!(1000) { return Number::new(value/Kiloohm.weight(), Kiloohm)
} else if value >= d!(1) { return Number::new(value, Ohm)
} else {
return Number::new(value/Milliohm.weight(), Milliohm)
}
} else if number.unit.category() == Voltage {
if value >= d!(1000) { return Number::new(value/Kilovolt.weight(), Kilovolt)
} else if value >= d!(1) { return Number::new(value, Volt)
} else {
return Number::new(value/Millivolt.weight(), Millivolt)
}
}
number
}
pub fn to_ideal_joule_unit(number: Number) -> Number {
let value = number.value * number.unit.weight();
if number.unit.category() == Energy {
if value >= d!(1000000000000) { return Number::new(value/Terajoule.weight(), Terajoule)
} else if value >= d!(1000000000) { return Number::new(value/Gigajoule.weight(), Gigajoule)
} else if value >= d!(1000000) { return Number::new(value/Megajoule.weight(), Megajoule)
} else if value >= d!(1000) { return Number::new(value/Kilojoule.weight(), Kilojoule)
} else if value >= d!(1) { return Number::new(value/Joule.weight(), Joule)
} else {
return Number::new(value/Millijoule.weight(), Millijoule)
}
}
number
}
pub fn multiply(left: Number, right: Number) -> Result<Number, String> {
actual_multiply(left, right, false)
}
fn actual_multiply(left: Number, right: Number, swapped: bool) -> Result<Number, String> {
let lcat = left.unit.category();
let rcat = right.unit.category();
if left.unit == NoUnit && right.unit == NoUnit {
Ok(Number::new(left.value * right.value, left.unit))
} else if left.unit.category() == Temperature || right.unit.category() == Temperature {
Err(format!("Cannot multiply {:?} and {:?}", left.unit, right.unit))
} else if left.unit == NoUnit && right.unit != NoUnit {
Ok(Number::new(left.value * right.value, right.unit))
} else if lcat == Length && rcat == Length {
let result = (left.value * left.unit.weight()) * (right.value * right.unit.weight());
Ok(to_ideal_unit(Number::new(result, SquareMillimeter)))
} else if lcat == Length && rcat == Area {
let result = (left.value * left.unit.weight()) * (right.value * right.unit.weight());
Ok(to_ideal_unit(Number::new(result, CubicMillimeter)))
} else if lcat == Speed && rcat == Time {
let kph_value = left.value * left.unit.weight();
let hours = convert(right, Hour)?;
let result = kph_value * hours.value;
let final_unit = match left.unit {
KilometersPerHour => Kilometer,
MetersPerSecond => Meter,
MilesPerHour => Mile,
FeetPerSecond => Foot,
Knot => NauticalMile,
_ => Meter,
};
let kilometers = Number::new(result, Kilometer);
Ok(convert(kilometers, final_unit)?)
} else if lcat == DataTransferRate && rcat == Time {
let data_rate_value = left.value * left.unit.weight();
let seconds = convert(right, Second)?;
let result = data_rate_value * seconds.value;
let final_unit = match left.unit {
BitsPerSecond => Bit,
KilobitsPerSecond => Kilobit,
MegabitsPerSecond => Megabit,
GigabitsPerSecond => Gigabit,
TerabitsPerSecond => Terabit,
PetabitsPerSecond => Petabit,
ExabitsPerSecond => Exabit,
ZettabitsPerSecond => Zettabit,
YottabitsPerSecond => Yottabit,
KibibitsPerSecond => Kibibit,
MebibitsPerSecond => Mebibit,
GibibitsPerSecond => Gibibit,
TebibitsPerSecond => Tebibit,
PebibitsPerSecond => Pebibit,
ExbibitsPerSecond => Exbibit,
ZebibitsPerSecond => Zebibit,
YobibitsPerSecond => Yobibit,
BytesPerSecond => Byte,
KilobytesPerSecond => Kilobyte,
MegabytesPerSecond => Megabyte,
GigabytesPerSecond => Gigabyte,
TerabytesPerSecond => Terabyte,
PetabytesPerSecond => Petabyte,
ExabytesPerSecond => Exabyte,
ZettabytesPerSecond => Zettabyte,
YottabytesPerSecond => Yottabyte,
KibibytesPerSecond => Kibibyte,
MebibytesPerSecond => Mebibyte,
GibibytesPerSecond => Gibibyte,
TebibytesPerSecond => Tebibyte,
PebibytesPerSecond => Pebibyte,
ExbibytesPerSecond => Exbibyte,
ZebibytesPerSecond => Zebibyte,
YobibytesPerSecond => Yobibyte,
_ => Bit,
};
let data_storage = Number::new(result, Bit);
Ok(convert(data_storage, final_unit)?)
} else if lcat == Voltage && rcat == ElectricCurrent {
let result = (left.value * left.unit.weight()) * (right.value * right.unit.weight());
Ok(to_ideal_unit(Number::new(result, Watt)))
} else if lcat == ElectricCurrent && rcat == Resistance {
let result = (left.value * left.unit.weight()) * (right.value * right.unit.weight());
Ok(to_ideal_unit(Number::new(result, Watt)))
} else if lcat == Power && rcat == Time {
let result = (left.value * left.unit.weight()) * (right.value * right.unit.weight() / Unit::Second.weight());
match right.unit {
Second => Ok(to_ideal_joule_unit(Number::new(result, Joule))),
_ => Ok(to_ideal_unit(Number::new(result, Joule))),
}
} else if swapped {
Err(format!("Cannot multiply {:?} and {:?}", right.unit, left.unit))
} else {
actual_multiply(right, left, true)
}
}
pub fn divide(left: Number, right: Number) -> Result<Number, String> {
let lcat = left.unit.category();
let rcat = right.unit.category();
if left.unit == NoUnit && right.unit == NoUnit {
Ok(Number::new(left.value / right.value, left.unit))
} else if lcat == Temperature || rcat == Temperature {
Err(format!("Cannot divide {:?} by {:?}", left.unit, right.unit))
} else if left.unit != NoUnit && right.unit == NoUnit {
Ok(Number::new(left.value / right.value, left.unit))
} else if lcat == rcat {
let (left, right) = convert_to_lowest(left, right)?;
Ok(Number::new(left.value / right.value, NoUnit))
} else if (lcat == Area && rcat == Length) || (lcat == Volume && rcat == Area) {
let result = (left.value * left.unit.weight()) / (right.value * right.unit.weight());
Ok(to_ideal_unit(Number::new(result, Millimeter)))
} else if lcat == Volume && rcat == Length {
let result = (left.value * left.unit.weight()) / (right.value * right.unit.weight());
Ok(to_ideal_unit(Number::new(result, SquareMillimeter)))
} else if lcat == Length && rcat == Time {
let final_unit = match (left.unit, right.unit) {
(Kilometer, Hour) => KilometersPerHour,
(Meter, Second) => MetersPerSecond,
(Mile, Hour) => MilesPerHour,
(Foot, Second) => FeetPerSecond,
(NauticalMile, Hour) => Knot,
_ => KilometersPerHour,
};
let kilometers = convert(left, Kilometer)?;
let hours = convert(right, Hour)?;
let kph = Number::new(kilometers.value / hours.value, KilometersPerHour);
Ok(convert(kph, final_unit)?)
} else if lcat == Length && rcat == Speed {
let kilometers = convert(left, Kilometer)?;
let kilometers_per_hour = convert(right, KilometersPerHour)?;
let hour = Number::new(kilometers.value / kilometers_per_hour.value, Hour);
Ok(to_ideal_unit(hour))
} else if lcat == DigitalStorage && rcat == DataTransferRate {
let bits = convert(left, Bit)?;
let bits_per_second = convert(right, BitsPerSecond)?;
let seconds = Number::new(bits.value / bits_per_second.value, Second);
Ok(to_ideal_unit(seconds))
} else if lcat == Power && rcat == ElectricCurrent {
let result = (left.value * left.unit.weight()) / (right.value * right.unit.weight());
Ok(to_ideal_unit(Number::new(result, Volt)))
} else if lcat == Voltage && rcat == ElectricCurrent {
let result = (left.value * left.unit.weight()) / (right.value * right.unit.weight());
Ok(to_ideal_unit(Number::new(result, Ohm)))
} else if lcat == Voltage && rcat == Resistance {
let result = (left.value * left.unit.weight()) / (right.value * right.unit.weight());
Ok(to_ideal_unit(Number::new(result, Ampere)))
} else if lcat == Power && rcat == Voltage {
let result = (left.value * left.unit.weight()) / (right.value * right.unit.weight());
Ok(to_ideal_unit(Number::new(result, Ampere)))
} else if lcat == Energy && rcat == Time {
let result = (left.value * left.unit.weight()) / (right.value * right.unit.weight() / Unit::Second.weight());
Ok(to_ideal_unit(Number::new(result, Watt)))
} else {
Err(format!("Cannot divide {:?} by {:?}", left.unit, right.unit))
}
}
pub fn modulo(left: Number, right: Number) -> Result<Number, String> {
if left.unit.category() == Temperature || right.unit.category() == Temperature {
Err(format!("Cannot modulo {:?} by {:?}", left.unit, right.unit))
} else if left.unit.category() == right.unit.category() {
let (left, right) = convert_to_lowest(left, right)?;
Ok(Number::new(left.value % right.value, left.unit))
} else {
Err(format!("Cannot modulo {:?} by {:?}", left.unit, right.unit))
}
}
fn do_pow(left: D128, right: D128) -> D128 {
let left = D256::try_from(left.transmute()).unwrap();
let right = D256::try_from(right.transmute()).unwrap();
let result = left.pow(right);
let result_d128: D128 = result.transmute();
result_d128
}
pub fn pow(left: Number, right: Number) -> Result<Number, String> {
let lcat = left.unit.category();
let rcat = left.unit.category();
if left.unit == NoUnit && right.unit == NoUnit {
Ok(Number::new(do_pow(left.value, right.value), left.unit))
} else if right.value == d!(1) && right.unit == NoUnit {
Ok(left)
} else if lcat == Length && right.unit == NoUnit && right.value == d!(2) {
let result = do_pow(left.value * left.unit.weight(), right.value);
Ok(to_ideal_unit(Number::new(result, SquareMillimeter)))
} else if lcat == Length && right.unit == NoUnit && right.value == d!(3) {
let result = do_pow(left.value * left.unit.weight(), right.value);
Ok(to_ideal_unit(Number::new(result, CubicMillimeter)))
} else if lcat == Length && rcat == Length && right.value == d!(1) {
Ok(multiply(left, right)?)
} else if lcat == Length && rcat == Length && right.value == d!(2) {
let pow2 = multiply(left, Number::new(d!(1), right.unit))?;
let pow3 = multiply(pow2, Number::new(d!(1), right.unit))?;
Ok(pow3)
} else if lcat == Length && rcat == Area && right.value == d!(1) {
Ok(multiply(left, Number::new(d!(1), right.unit))?)
} else {
Err(format!("Cannot multiply {:?} and {:?}", left.unit, right.unit))
}
}
#[cfg(test)]
mod tests {
use fastnum::decimal::Context;
use super::*;
macro_rules! assert_float_eq {
( $actual:expr, $expected:literal ) => {
assert!(($actual - $expected).abs() < f64::EPSILON);
}
}
#[test]
fn test_convert() {
pub fn convert_test(value: f64, unit: Unit, to_unit: Unit) -> f64 {
use std::str::FromStr;
let value_string = &value.to_string();
let value_d128 = D128::from_str(value_string, Context::default()).unwrap();
let number = Number::new(value_d128, unit);
let result = convert(number, to_unit);
let string_result = &result.unwrap().value.to_string();
let float_result = f64::from_str(string_result).unwrap();
return float_result;
}
assert_float_eq!(convert_test(1000.0, Nanosecond, Microsecond), 1.0);
assert_float_eq!(convert_test(1000.0, Nanosecond, Microsecond), 1.0);
assert_float_eq!(convert_test(1000.0, Microsecond, Millisecond), 1.0);
assert_float_eq!(convert_test(1000.0, Millisecond, Second), 1.0);
assert_float_eq!(convert_test(60.0, Second, Minute), 1.0);
assert_float_eq!(convert_test(60.0, Minute, Hour), 1.0);
assert_float_eq!(convert_test(24.0, Hour, Day), 1.0);
assert_float_eq!(convert_test(7.0, Day, Week), 1.0);
assert_float_eq!(convert_test(30.436875, Day, Month), 1.0);
assert_float_eq!(convert_test(3.0, Month, Quarter), 1.0);
assert_float_eq!(convert_test(4.0, Quarter, Year), 1.0);
assert_float_eq!(convert_test(10.0, Year, Decade), 1.0);
assert_float_eq!(convert_test(10.0, Decade, Century), 1.0);
assert_float_eq!(convert_test(10.0, Century, Millenium), 1.0);
assert_float_eq!(convert_test(10.0, Millimeter, Centimeter), 1.0);
assert_float_eq!(convert_test(10.0, Centimeter, Decimeter), 1.0);
assert_float_eq!(convert_test(10.0, Decimeter, Meter), 1.0);
assert_float_eq!(convert_test(1000.0, Meter, Kilometer), 1.0);
assert_float_eq!(convert_test(2.54, Centimeter, Inch), 1.0);
assert_float_eq!(convert_test(12.0, Inch, Foot), 1.0);
assert_float_eq!(convert_test(3.0, Foot, Yard), 1.0);
assert_float_eq!(convert_test(1760.0, Yard, Mile), 1.0);
assert_float_eq!(convert_test(42195.0, Meter, Marathon), 1.0);
assert_float_eq!(convert_test(1852.0, Meter, NauticalMile), 1.0);
assert_float_eq!(convert_test(9460730472580800.0, Meter, LightYear), 1.0);
assert_float_eq!(convert_test(299792458.0, Meter, LightSecond), 1.0);
assert_float_eq!(convert_test(100.0, SquareMillimeter, SquareCentimeter), 1.0);
assert_float_eq!(convert_test(100.0, SquareCentimeter, SquareDecimeter), 1.0);
assert_float_eq!(convert_test(100.0, SquareDecimeter, SquareMeter), 1.0);
assert_float_eq!(convert_test(1000000.0, SquareMeter, SquareKilometer), 1.0);
assert_float_eq!(convert_test(645.16, SquareMillimeter, SquareInch), 1.0);
assert_float_eq!(convert_test(144.0, SquareInch, SquareFoot), 1.0);
assert_float_eq!(convert_test(9.0, SquareFoot, SquareYard), 1.0);
assert_float_eq!(convert_test(3097600.0, SquareYard, SquareMile), 1.0);
assert_float_eq!(convert_test(100.0, SquareMeter, Are), 1.0);
assert_float_eq!(convert_test(10.0, Are, Decare), 1.0);
assert_float_eq!(convert_test(10.0, Decare, Hectare), 1.0);
assert_float_eq!(convert_test(640.0, Acre, SquareMile), 1.0);
assert_float_eq!(convert_test(1000.0, CubicMillimeter, CubicCentimeter), 1.0);
assert_float_eq!(convert_test(1000.0, CubicCentimeter, CubicDecimeter), 1.0);
assert_float_eq!(convert_test(1000.0, CubicDecimeter, CubicMeter), 1.0);
assert_float_eq!(convert_test(1000000000.0, CubicMeter, CubicKilometer), 1.0);
assert_float_eq!(convert_test(1728.0, CubicInch, CubicFoot), 1.0);
assert_float_eq!(convert_test(27.0, CubicFoot, CubicYard), 1.0);
assert_float_eq!(convert_test(5451776000.0, CubicYard, CubicMile), 1.0);
assert_float_eq!(convert_test(1.0, Milliliter, CubicCentimeter), 1.0);
assert_float_eq!(convert_test(10.0, Milliliter, Centiliter), 1.0);
assert_float_eq!(convert_test(10.0, Centiliter, Deciliter), 1.0);
assert_float_eq!(convert_test(10.0, Deciliter, Liter), 1.0);
assert_float_eq!(convert_test(4.92892159375, Milliliter, Teaspoon), 1.0);
assert_float_eq!(convert_test(3.0, Teaspoon, Tablespoon), 1.0);
assert_float_eq!(convert_test(2.0, Tablespoon, FluidOunce), 1.0);
assert_float_eq!(convert_test(8.0, FluidOunce, Cup), 1.0);
assert_float_eq!(convert_test(2.0, Cup, Pint), 1.0);
assert_float_eq!(convert_test(2.0, Pint, Quart), 1.0);
assert_float_eq!(convert_test(4.0, Quart, Gallon), 1.0);
assert_float_eq!(convert_test(42.0, Gallon, OilBarrel), 1.0);
assert_float_eq!(convert_test(1000.0, Milligram, Gram), 1.0);
assert_float_eq!(convert_test(100.0, Gram, Hectogram), 1.0);
assert_float_eq!(convert_test(1000.0, Gram, Kilogram), 1.0);
assert_float_eq!(convert_test(1000.0, Kilogram, MetricTon), 1.0);
assert_float_eq!(convert_test(0.45359237, Kilogram, Pound), 1.0);
assert_float_eq!(convert_test(16.0, Ounce, Pound), 1.0);
assert_float_eq!(convert_test(14.0, Pound, Stone), 1.0);
assert_float_eq!(convert_test(2000.0, Pound, ShortTon), 1.0);
assert_float_eq!(convert_test(2240.0, Pound, LongTon), 1.0);
assert_float_eq!(convert_test(1000.0, Bit, Kilobit), 1.0);
assert_float_eq!(convert_test(1000.0, Kilobit, Megabit), 1.0);
assert_float_eq!(convert_test(1000.0, Megabit, Gigabit), 1.0);
assert_float_eq!(convert_test(1000.0, Gigabit, Terabit), 1.0);
assert_float_eq!(convert_test(1000.0, Terabit, Petabit), 1.0);
assert_float_eq!(convert_test(1000.0, Petabit, Exabit), 1.0);
assert_float_eq!(convert_test(1000.0, Exabit, Zettabit), 1.0);
assert_float_eq!(convert_test(1000.0, Zettabit, Yottabit), 1.0);
assert_float_eq!(convert_test(1024.0, Bit, Kibibit), 1.0);
assert_float_eq!(convert_test(1024.0, Kibibit, Mebibit), 1.0);
assert_float_eq!(convert_test(1024.0, Mebibit, Gibibit), 1.0);
assert_float_eq!(convert_test(1024.0, Gibibit, Tebibit), 1.0);
assert_float_eq!(convert_test(1024.0, Tebibit, Pebibit), 1.0);
assert_float_eq!(convert_test(1024.0, Pebibit, Exbibit), 1.0);
assert_float_eq!(convert_test(1024.0, Exbibit, Zebibit), 1.0);
assert_float_eq!(convert_test(1024.0, Zebibit, Yobibit), 1.0);
assert_float_eq!(convert_test(8.0, Bit, Byte), 1.0);
assert_float_eq!(convert_test(1000.0, Byte, Kilobyte), 1.0);
assert_float_eq!(convert_test(1000.0, Kilobyte, Megabyte), 1.0);
assert_float_eq!(convert_test(1000.0, Megabyte, Gigabyte), 1.0);
assert_float_eq!(convert_test(1000.0, Gigabyte, Terabyte), 1.0);
assert_float_eq!(convert_test(1000.0, Terabyte, Petabyte), 1.0);
assert_float_eq!(convert_test(1000.0, Petabyte, Exabyte), 1.0);
assert_float_eq!(convert_test(1000.0, Exabyte, Zettabyte), 1.0);
assert_float_eq!(convert_test(1000.0, Zettabyte, Yottabyte), 1.0);
assert_float_eq!(convert_test(1024.0, Kibibyte, Mebibyte), 1.0);
assert_float_eq!(convert_test(1024.0, Mebibyte, Gibibyte), 1.0);
assert_float_eq!(convert_test(1024.0, Gibibyte, Tebibyte), 1.0);
assert_float_eq!(convert_test(1024.0, Tebibyte, Pebibyte), 1.0);
assert_float_eq!(convert_test(1024.0, Pebibyte, Exbibyte), 1.0);
assert_float_eq!(convert_test(1024.0, Exbibyte, Zebibyte), 1.0);
assert_float_eq!(convert_test(1024.0, Zebibyte, Yobibyte), 1.0);
assert_float_eq!(convert_test(1000.0, BitsPerSecond, KilobitsPerSecond), 1.0);
assert_float_eq!(convert_test(1000.0, KilobitsPerSecond, MegabitsPerSecond), 1.0);
assert_float_eq!(convert_test(1000.0, MegabitsPerSecond, GigabitsPerSecond), 1.0);
assert_float_eq!(convert_test(1000.0, GigabitsPerSecond, TerabitsPerSecond), 1.0);
assert_float_eq!(convert_test(1000.0, TerabitsPerSecond, PetabitsPerSecond), 1.0);
assert_float_eq!(convert_test(1000.0, PetabitsPerSecond, ExabitsPerSecond), 1.0);
assert_float_eq!(convert_test(1000.0, ExabitsPerSecond, ZettabitsPerSecond), 1.0);
assert_float_eq!(convert_test(1000.0, ZettabitsPerSecond, YottabitsPerSecond), 1.0);
assert_float_eq!(convert_test(1024.0, BitsPerSecond, KibibitsPerSecond), 1.0);
assert_float_eq!(convert_test(1024.0, KibibitsPerSecond, MebibitsPerSecond), 1.0);
assert_float_eq!(convert_test(1024.0, MebibitsPerSecond, GibibitsPerSecond), 1.0);
assert_float_eq!(convert_test(1024.0, GibibitsPerSecond, TebibitsPerSecond), 1.0);
assert_float_eq!(convert_test(1024.0, TebibitsPerSecond, PebibitsPerSecond), 1.0);
assert_float_eq!(convert_test(1024.0, PebibitsPerSecond, ExbibitsPerSecond), 1.0);
assert_float_eq!(convert_test(1024.0, ExbibitsPerSecond, ZebibitsPerSecond), 1.0);
assert_float_eq!(convert_test(1024.0, ZebibitsPerSecond, YobibitsPerSecond), 1.0);
assert_float_eq!(convert_test(8.0, BitsPerSecond, BytesPerSecond), 1.0);
assert_float_eq!(convert_test(1000.0, BytesPerSecond, KilobytesPerSecond), 1.0);
assert_float_eq!(convert_test(1000.0, KilobytesPerSecond, MegabytesPerSecond), 1.0);
assert_float_eq!(convert_test(1000.0, MegabytesPerSecond, GigabytesPerSecond), 1.0);
assert_float_eq!(convert_test(1000.0, GigabytesPerSecond, TerabytesPerSecond), 1.0);
assert_float_eq!(convert_test(1000.0, TerabytesPerSecond, PetabytesPerSecond), 1.0);
assert_float_eq!(convert_test(1000.0, PetabytesPerSecond, ExabytesPerSecond), 1.0);
assert_float_eq!(convert_test(1000.0, ExabytesPerSecond, ZettabytesPerSecond), 1.0);
assert_float_eq!(convert_test(1000.0, ZettabytesPerSecond, YottabytesPerSecond), 1.0);
assert_float_eq!(convert_test(1024.0, KibibytesPerSecond, MebibytesPerSecond), 1.0);
assert_float_eq!(convert_test(1024.0, MebibytesPerSecond, GibibytesPerSecond), 1.0);
assert_float_eq!(convert_test(1024.0, GibibytesPerSecond, TebibytesPerSecond), 1.0);
assert_float_eq!(convert_test(1024.0, TebibytesPerSecond, PebibytesPerSecond), 1.0);
assert_float_eq!(convert_test(1024.0, PebibytesPerSecond, ExbibytesPerSecond), 1.0);
assert_float_eq!(convert_test(1024.0, ExbibytesPerSecond, ZebibytesPerSecond), 1.0);
assert_float_eq!(convert_test(1024.0, ZebibytesPerSecond, YobibytesPerSecond), 1.0);
assert_float_eq!(convert_test(1000.0, Millijoule, Joule), 1.0);
assert_float_eq!(convert_test(1000.0, Joule, Kilojoule), 1.0);
assert_float_eq!(convert_test(1.0, NewtonMeter, Joule), 1.0);
assert_float_eq!(convert_test(1000.0, Kilojoule, Megajoule), 1.0);
assert_float_eq!(convert_test(1000.0, Megajoule, Gigajoule), 1.0);
assert_float_eq!(convert_test(1000.0, Gigajoule, Terajoule), 1.0);
assert_float_eq!(convert_test(4.1868, Joule, Calorie), 1.0);
assert_float_eq!(convert_test(1000.0, Calorie, KiloCalorie), 1.0);
assert_float_eq!(convert_test(1055.05585262, Joule, BritishThermalUnit), 1.0);
assert_float_eq!(convert_test(3600.0, Joule, WattHour), 1.0);
assert_float_eq!(convert_test(1000.0, WattHour, KilowattHour), 1.0);
assert_float_eq!(convert_test(1000.0, KilowattHour, MegawattHour), 1.0);
assert_float_eq!(convert_test(1000.0, MegawattHour, GigawattHour), 1.0);
assert_float_eq!(convert_test(1000.0, GigawattHour, TerawattHour), 1.0);
assert_float_eq!(convert_test(1000.0, TerawattHour, PetawattHour), 1.0);
assert_float_eq!(convert_test(1000.0, Milliwatt, Watt), 1.0);
assert_float_eq!(convert_test(1000.0, Watt, Kilowatt), 1.0);
assert_float_eq!(convert_test(1000.0, Kilowatt, Megawatt), 1.0);
assert_float_eq!(convert_test(1000.0, Megawatt, Gigawatt), 1.0);
assert_float_eq!(convert_test(1000.0, Gigawatt, Terawatt), 1.0);
assert_float_eq!(convert_test(1000.0, Terawatt, Petawatt), 1.0);
assert_float_eq!(convert_test(0.0568690272188, Watt, BritishThermalUnitsPerMinute), 1.0);
assert_float_eq!(convert_test(60.0, BritishThermalUnitsPerMinute, BritishThermalUnitsPerHour), 1.0);
assert_float_eq!(convert_test(745.6998715822702, Watt, Horsepower), 1.0);
assert_float_eq!(convert_test(735.49875, Watt, MetricHorsepower), 1.0);
assert_float_eq!(convert_test(1000.0, Milliampere, Ampere), 1.0);
assert_float_eq!(convert_test(1000.0, Ampere, Kiloampere), 1.0);
assert_float_eq!(convert_test(10.0, Ampere, Abampere), 1.0);
assert_float_eq!(convert_test(1000.0, Milliohm, Ohm), 1.0);
assert_float_eq!(convert_test(1000.0, Ohm, Kiloohm), 1.0);
assert_float_eq!(convert_test(1000.0, Millivolt, Volt), 1.0);
assert_float_eq!(convert_test(1000.0, Volt, Kilovolt), 1.0);
assert_float_eq!(convert_test(1000.0, Pascal, Kilopascal), 1.0);
assert_float_eq!(convert_test(101325.0, Pascal, Atmosphere), 1.0);
assert_float_eq!(convert_test(100.0, Pascal, Millibar), 1.0);
assert_float_eq!(convert_test(1000.0, Millibar, Bar), 1.0);
assert_float_eq!(convert_test(3386.389, Pascal, InchOfMercury), 1.0);
assert_float_eq!(convert_test(6894.757293168361, Pascal, PoundsPerSquareInch), 1.0);
assert_float_eq!(convert_test(162.12, Pascal, Torr), 1.0);
assert_float_eq!(convert_test(1000.0, Hertz, Kilohertz), 1.0);
assert_float_eq!(convert_test(1000.0, Kilohertz, Megahertz), 1.0);
assert_float_eq!(convert_test(1000.0, Megahertz, Gigahertz), 1.0);
assert_float_eq!(convert_test(1000.0, Gigahertz, Terahertz), 1.0);
assert_float_eq!(convert_test(1000.0, Terahertz, Petahertz), 1.0);
assert_float_eq!(convert_test(60.0, Hertz, RevolutionsPerMinute), 1.0);
assert_float_eq!(convert_test(3.6, KilometersPerHour, MetersPerSecond), 1.0);
assert_float_eq!(convert_test(0.3048, MetersPerSecond, FeetPerSecond), 1.0);
assert_float_eq!(convert_test(1.609344, KilometersPerHour, MilesPerHour), 1.0);
assert_float_eq!(convert_test(1.852, KilometersPerHour, Knot), 1.0);
assert_float_eq!(convert_test(274.15, Kelvin, Celsius), 1.0);
assert_float_eq!(convert_test(300.0, Kelvin, Fahrenheit), 80.33);
assert_float_eq!(convert_test(-272.15, Celsius, Kelvin), 1.0);
assert_float_eq!(convert_test(-15.0, Celsius, Fahrenheit), 5.0);
assert_float_eq!(convert_test(80.33, Fahrenheit, Kelvin), 300.0);
assert_float_eq!(convert_test(5.0, Fahrenheit, Celsius), -15.0);
}
}