Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 112 additions & 0 deletions src/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,30 @@ fn parse_word(word: &str, lexer: &mut Lexer) -> Result<(), String> {
"zbps" => Token::Unit(ZettabitsPerSecond),
"ybps" => Token::Unit(YottabitsPerSecond),

"flop" => Token::Unit(FLOP),
"kflop" | "kiloflop" => Token::Unit(KiloFLOP),
"mflop" | "megaflop" => Token::Unit(MegaFLOP),
"gflop" | "gigaflop" => Token::Unit(GigaFLOP),
"tflop" | "teraflop" => Token::Unit(TeraFLOP),
"pflop" | "petaflop" => Token::Unit(PetaFLOP),
"eflop" | "exaflop" => Token::Unit(ExaFLOP),
"zflop" | "zettaflop" => Token::Unit(ZettaFLOP),
"yflop" | "yottaflop" => Token::Unit(YottaFLOP),
"rflop" | "ronnaflop" => Token::Unit(RonnaFLOP),
"qflop" | "quettaflop" => Token::Unit(QuettaFLOP),

"flops" => Token::Unit(FLOPPerSecond),
"kflops" | "kiloflops" => Token::Unit(KiloFLOPPerSecond),
"mflops" | "megaflops" => Token::Unit(MegaFLOPPerSecond),
"gflops" | "gigaflops" => Token::Unit(GigaFLOPPerSecond),
"tflops" | "teraflops" => Token::Unit(TeraFLOPPerSecond),
"pflops" | "petaflops" => Token::Unit(PetaFLOPPerSecond),
"eflops" | "exaflops" => Token::Unit(ExaFLOPPerSecond),
"zflops" | "zettaflops" => Token::Unit(ZettaFLOPPerSecond),
"yflops" | "yottaflops" => Token::Unit(YottaFLOPPerSecond),
"rflops" | "ronnaflops" => Token::Unit(RonnaFLOPPerSecond),
"qflops" | "quettaflops" => Token::Unit(QuettaFLOPPerSecond),

"millijoule" | "millijoules" => Token::Unit(Millijoule),
"j"| "joule" | "joules" => Token::Unit(Joule),
"nm" => Token::Unit(NewtonMeter),
Expand Down Expand Up @@ -883,6 +907,50 @@ pub fn lex(input: &str, remove_trailing_operator: bool) -> Result<Vec<Token>, St
(Token::Unit(Yobibyte), Token::LexerKeyword(Per), Token::Unit(Second)) => {
tokens[token_index-2] = Token::Unit(YobibytesPerSecond);
},
// FLOP per second
(Token::Unit(FLOP), Token::LexerKeyword(Per), Token::Unit(Second)) => {
tokens[token_index-2] = Token::Unit(FLOPPerSecond);
},
// kiloFLOP per second
(Token::Unit(KiloFLOP), Token::LexerKeyword(Per), Token::Unit(Second)) => {
tokens[token_index-2] = Token::Unit(KiloFLOPPerSecond);
},
// megaFLOP per second
(Token::Unit(MegaFLOP), Token::LexerKeyword(Per), Token::Unit(Second)) => {
tokens[token_index-2] = Token::Unit(MegaFLOPPerSecond);
},
// gigaFLOP per second
(Token::Unit(GigaFLOP), Token::LexerKeyword(Per), Token::Unit(Second)) => {
tokens[token_index-2] = Token::Unit(GigaFLOPPerSecond);
},
// teraFLOP per second
(Token::Unit(TeraFLOP), Token::LexerKeyword(Per), Token::Unit(Second)) => {
tokens[token_index-2] = Token::Unit(TeraFLOPPerSecond);
},
// petaFLOP per second
(Token::Unit(PetaFLOP), Token::LexerKeyword(Per), Token::Unit(Second)) => {
tokens[token_index-2] = Token::Unit(PetaFLOPPerSecond);
},
// exaFLOP per second
(Token::Unit(ExaFLOP), Token::LexerKeyword(Per), Token::Unit(Second)) => {
tokens[token_index-2] = Token::Unit(ExaFLOPPerSecond);
},
// zettaFLOP per second
(Token::Unit(ZettaFLOP), Token::LexerKeyword(Per), Token::Unit(Second)) => {
tokens[token_index-2] = Token::Unit(ZettaFLOPPerSecond);
},
// yottaFLOP per second
(Token::Unit(YottaFLOP), Token::LexerKeyword(Per), Token::Unit(Second)) => {
tokens[token_index-2] = Token::Unit(YottaFLOPPerSecond);
},
// ronnaFLOP per second
(Token::Unit(RonnaFLOP), Token::LexerKeyword(Per), Token::Unit(Second)) => {
tokens[token_index-2] = Token::Unit(RonnaFLOPPerSecond);
},
// quettaFLOP per second
(Token::Unit(QuettaFLOP), Token::LexerKeyword(Per), Token::Unit(Second)) => {
tokens[token_index-2] = Token::Unit(QuettaFLOPPerSecond);
},
// btu/min
(Token::Unit(BritishThermalUnit), Token::LexerKeyword(Per), Token::Unit(Minute)) => {
tokens[token_index-2] = Token::Unit(BritishThermalUnitsPerMinute);
Expand Down Expand Up @@ -1085,6 +1153,50 @@ mod tests {
run_datarate_lex("18 exbibytes per second", vec![numtok!(18), Token::Unit(ExbibytesPerSecond)]);
run_datarate_lex("19 zebibytes per second", vec![numtok!(19), Token::Unit(ZebibytesPerSecond)]);
run_datarate_lex("20 yobibytes per second", vec![numtok!(20), Token::Unit(YobibytesPerSecond)]);
run_lex("1 flop", vec![numtok!(1), Token::Unit(FLOP)]);
run_lex("2 kflop", vec![numtok!(2), Token::Unit(KiloFLOP)]);
run_lex("3 mflop", vec![numtok!(3), Token::Unit(MegaFLOP)]);
run_lex("4 gflop", vec![numtok!(4), Token::Unit(GigaFLOP)]);
run_lex("5 tflop", vec![numtok!(5), Token::Unit(TeraFLOP)]);
run_lex("6 pflop", vec![numtok!(6), Token::Unit(PetaFLOP)]);
run_lex("7 eflop", vec![numtok!(7), Token::Unit(ExaFLOP)]);
run_lex("8 zflop", vec![numtok!(8), Token::Unit(ZettaFLOP)]);
run_lex("9 yflop", vec![numtok!(9), Token::Unit(YottaFLOP)]);
run_lex("10 rflop", vec![numtok!(10), Token::Unit(RonnaFLOP)]);
run_lex("11 qflop", vec![numtok!(11), Token::Unit(QuettaFLOP)]);
run_lex("1 flop/s", vec![numtok!(1), Token::Unit(FLOPPerSecond)]);
run_lex("2 kflop/s", vec![numtok!(2), Token::Unit(KiloFLOPPerSecond)]);
run_lex("3 mflop/s", vec![numtok!(3), Token::Unit(MegaFLOPPerSecond)]);
run_lex("4 gflop/s", vec![numtok!(4), Token::Unit(GigaFLOPPerSecond)]);
run_lex("5 tflop/s", vec![numtok!(5), Token::Unit(TeraFLOPPerSecond)]);
run_lex("6 pflop/s", vec![numtok!(6), Token::Unit(PetaFLOPPerSecond)]);
run_lex("7 eflop/s", vec![numtok!(7), Token::Unit(ExaFLOPPerSecond)]);
run_lex("8 zflop/s", vec![numtok!(8), Token::Unit(ZettaFLOPPerSecond)]);
run_lex("9 yflop/s", vec![numtok!(9), Token::Unit(YottaFLOPPerSecond)]);
run_lex("10 rflop/s", vec![numtok!(10), Token::Unit(RonnaFLOPPerSecond)]);
run_lex("11 qflop/s", vec![numtok!(11), Token::Unit(QuettaFLOPPerSecond)]);
run_lex("1 flop per second", vec![numtok!(1), Token::Unit(FLOPPerSecond)]);
run_lex("2 kflop per second", vec![numtok!(2), Token::Unit(KiloFLOPPerSecond)]);
run_lex("3 mflop per second", vec![numtok!(3), Token::Unit(MegaFLOPPerSecond)]);
run_lex("4 gflop per second", vec![numtok!(4), Token::Unit(GigaFLOPPerSecond)]);
run_lex("5 tflop per second", vec![numtok!(5), Token::Unit(TeraFLOPPerSecond)]);
run_lex("6 pflop per second", vec![numtok!(6), Token::Unit(PetaFLOPPerSecond)]);
run_lex("7 eflop per second", vec![numtok!(7), Token::Unit(ExaFLOPPerSecond)]);
run_lex("8 zflop per second", vec![numtok!(8), Token::Unit(ZettaFLOPPerSecond)]);
run_lex("9 yflop per second", vec![numtok!(9), Token::Unit(YottaFLOPPerSecond)]);
run_lex("10 rflop per second", vec![numtok!(10), Token::Unit(RonnaFLOPPerSecond)]);
run_lex("11 qflop per second", vec![numtok!(11), Token::Unit(QuettaFLOPPerSecond)]);
run_lex("1 flops", vec![numtok!(1), Token::Unit(FLOPPerSecond)]);
run_lex("2 kflops", vec![numtok!(2), Token::Unit(KiloFLOPPerSecond)]);
run_lex("3 mflops", vec![numtok!(3), Token::Unit(MegaFLOPPerSecond)]);
run_lex("4 gflops", vec![numtok!(4), Token::Unit(GigaFLOPPerSecond)]);
run_lex("5 tflops", vec![numtok!(5), Token::Unit(TeraFLOPPerSecond)]);
run_lex("6 pflops", vec![numtok!(6), Token::Unit(PetaFLOPPerSecond)]);
run_lex("7 eflops", vec![numtok!(7), Token::Unit(ExaFLOPPerSecond)]);
run_lex("8 zflops", vec![numtok!(8), Token::Unit(ZettaFLOPPerSecond)]);
run_lex("9 yflops", vec![numtok!(9), Token::Unit(YottaFLOPPerSecond)]);
run_lex("10 rflops", vec![numtok!(10), Token::Unit(RonnaFLOPPerSecond)]);
run_lex("11 qflops", vec![numtok!(11), Token::Unit(QuettaFLOPPerSecond)]);
run_lex("234 wh", vec![numtok!(234), Token::Unit(WattHour)]);
run_lex("1 w", vec![numtok!(1), Token::Unit(Watt)]);
run_lex("1 watt", vec![numtok!(1), Token::Unit(Watt)]);
Expand Down
77 changes: 77 additions & 0 deletions src/units.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ pub enum UnitType {
DigitalStorage,
/// A unit of data rate transfer, for example [`KilobytesPerSecond`]
DataTransferRate,
/// A unit of computational work, for example [`KiloFLOP`]
ComputationalWork,
/// A unit of computational performance, for example [`KiloFLOPPerSecond`]
ComputationalPerformance,
/// A unit of energy, for example [`Joule`] or [`KilowattHour`]
Energy,
/// A unit of power, for example [`Watt`]
Expand Down Expand Up @@ -239,6 +243,30 @@ create_units!(
ZebibytesPerSecond: (DataTransferRate, d!(9444732965739290427392), "zebibyte per second", "zebibytes per second"),
YobibytesPerSecond: (DataTransferRate, d!(9671406556917033397649408), "yobibyte per second", "yobibytes per second"),

FLOP: (ComputationalWork, d!(1), "FLOP", "FLOP"),
KiloFLOP: (ComputationalWork, d!(1000), "kiloFLOP", "kiloFLOP"),
MegaFLOP: (ComputationalWork, d!(1000000), "megaFLOP", "megaFLOP"),
GigaFLOP: (ComputationalWork, d!(1000000000), "gigaFLOP", "gigaFLOP"),
TeraFLOP: (ComputationalWork, d!(1000000000000), "teraFLOP", "teraFLOP"),
PetaFLOP: (ComputationalWork, d!(1000000000000000), "petaFLOP", "petaFLOP"),
ExaFLOP: (ComputationalWork, d!(1000000000000000000), "exaFLOP", "exaFLOP"),
ZettaFLOP: (ComputationalWork, d!(1000000000000000000000), "zettaFLOP", "zettaFLOP"),
YottaFLOP: (ComputationalWork, d!(1000000000000000000000000), "yottaFLOP", "yottaFLOP"),
RonnaFLOP: (ComputationalWork, d!(1000000000000000000000000000), "ronnaFLOP", "ronnaFLOP"),
QuettaFLOP: (ComputationalWork, d!(1000000000000000000000000000000), "quettaFLOP", "quettaFLOP"),

FLOPPerSecond: (ComputationalPerformance, d!(1), "FLOP per second", "FLOP per second"),
KiloFLOPPerSecond: (ComputationalPerformance, d!(1000), "kiloFLOP per second", "kiloFLOP per second"),
MegaFLOPPerSecond: (ComputationalPerformance, d!(1000000), "megaFLOP per second", "megaFLOP per second"),
GigaFLOPPerSecond: (ComputationalPerformance, d!(1000000000), "gigaFLOP per second", "gigaFLOP per second"),
TeraFLOPPerSecond: (ComputationalPerformance, d!(1000000000000), "teraFLOP per second", "teraFLOP per second"),
PetaFLOPPerSecond: (ComputationalPerformance, d!(1000000000000000), "petaFLOP per second", "petaFLOP per second"),
ExaFLOPPerSecond: (ComputationalPerformance, d!(1000000000000000000), "exaFLOP per second", "exaFLOP per second"),
ZettaFLOPPerSecond: (ComputationalPerformance, d!(1000000000000000000000), "zettaFLOP per second", "zettaFLOP per second"),
YottaFLOPPerSecond: (ComputationalPerformance, d!(1000000000000000000000000), "yottaFLOP per second", "yottaFLOP per second"),
RonnaFLOPPerSecond: (ComputationalPerformance, d!(1000000000000000000000000000), "ronnaFLOP per second", "ronnaFLOP per second"),
QuettaFLOPPerSecond: (ComputationalPerformance, d!(1000000000000000000000000000000), "quettaFLOP per second", "quettaFLOP per second"),

Millijoule: (Energy, d!(0.001), "millijoule", "millijoules"),
Joule: (Energy, d!(1), "joule", "joules"),
NewtonMeter: (Energy, d!(1), "newton meter", "newton meters"),
Expand Down Expand Up @@ -628,6 +656,27 @@ fn actual_multiply(left: Number, right: Number, swapped: bool) -> Result<Number,
};
let data_storage = Number::new(result, Bit);
Ok(convert(data_storage, final_unit)?)
} else if lcat == ComputationalPerformance && rcat == Time {
// 8 megaFLOP per second * 1 minute
let compute_perf_value = left.value * left.unit.weight();
let seconds = convert(right, Second)?;
let result = compute_perf_value * seconds.value;
let final_unit = match left.unit {
FLOPPerSecond => FLOP,
KiloFLOPPerSecond => KiloFLOP,
MegaFLOPPerSecond => MegaFLOP,
GigaFLOPPerSecond => GigaFLOP,
TeraFLOPPerSecond => TeraFLOP,
PetaFLOPPerSecond => PetaFLOP,
ExaFLOPPerSecond => ExaFLOP,
ZettaFLOPPerSecond => ZettaFLOP,
YottaFLOPPerSecond => YottaFLOP,
RonnaFLOPPerSecond => RonnaFLOP,
QuettaFLOPPerSecond => QuettaFLOP,
_ => FLOP,
};
let compute_work = Number::new(result, FLOP);
Ok(convert(compute_work, final_unit)?)
} else if lcat == Voltage && rcat == ElectricCurrent {
// 1 volt * 1 ampere = 1 watt
let result = (left.value * left.unit.weight()) * (right.value * right.unit.weight());
Expand Down Expand Up @@ -712,6 +761,12 @@ pub fn divide(left: Number, right: Number) -> Result<Number, String> {
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 == ComputationalWork && rcat == ComputationalPerformance {
// 1 kiloFLOP / 1 FLOP per second
let flop = convert(left, FLOP)?;
let flop_per_second = convert(right, FLOPPerSecond)?;
let seconds = Number::new(flop.value / flop_per_second.value, Second);
Ok(to_ideal_unit(seconds))
} else if lcat == Power && rcat == ElectricCurrent {
// 1 watt / 1 ampere = 1 volt
let result = (left.value * left.unit.weight()) / (right.value * right.unit.weight());
Expand Down Expand Up @@ -958,6 +1013,28 @@ use super::*;
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, FLOP, KiloFLOP), 1.0);
assert_float_eq!(convert_test(1000.0, KiloFLOP, MegaFLOP), 1.0);
assert_float_eq!(convert_test(1000.0, MegaFLOP, GigaFLOP), 1.0);
assert_float_eq!(convert_test(1000.0, GigaFLOP, TeraFLOP), 1.0);
assert_float_eq!(convert_test(1000.0, TeraFLOP, PetaFLOP), 1.0);
assert_float_eq!(convert_test(1000.0, PetaFLOP, ExaFLOP), 1.0);
assert_float_eq!(convert_test(1000.0, ExaFLOP, ZettaFLOP), 1.0);
assert_float_eq!(convert_test(1000.0, ZettaFLOP, YottaFLOP), 1.0);
assert_float_eq!(convert_test(1000.0, YottaFLOP, RonnaFLOP), 1.0);
assert_float_eq!(convert_test(1000.0, RonnaFLOP, QuettaFLOP), 1.0);

assert_float_eq!(convert_test(1000.0, FLOPPerSecond, KiloFLOPPerSecond), 1.0);
assert_float_eq!(convert_test(1000.0, KiloFLOPPerSecond, MegaFLOPPerSecond), 1.0);
assert_float_eq!(convert_test(1000.0, MegaFLOPPerSecond, GigaFLOPPerSecond), 1.0);
assert_float_eq!(convert_test(1000.0, GigaFLOPPerSecond, TeraFLOPPerSecond), 1.0);
assert_float_eq!(convert_test(1000.0, TeraFLOPPerSecond, PetaFLOPPerSecond), 1.0);
assert_float_eq!(convert_test(1000.0, PetaFLOPPerSecond, ExaFLOPPerSecond), 1.0);
assert_float_eq!(convert_test(1000.0, ExaFLOPPerSecond, ZettaFLOPPerSecond), 1.0);
assert_float_eq!(convert_test(1000.0, ZettaFLOPPerSecond, YottaFLOPPerSecond), 1.0);
assert_float_eq!(convert_test(1000.0, YottaFLOPPerSecond, RonnaFLOPPerSecond), 1.0);
assert_float_eq!(convert_test(1000.0, RonnaFLOPPerSecond, QuettaFLOPPerSecond), 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);
Expand Down