diff --git a/src/lexer.rs b/src/lexer.rs index fb9f2a0..5af154c 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -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), @@ -883,6 +907,50 @@ pub fn lex(input: &str, remove_trailing_operator: bool) -> Result, 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); @@ -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)]); diff --git a/src/units.rs b/src/units.rs index d095cad..bfbe8e4 100644 --- a/src/units.rs +++ b/src/units.rs @@ -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`] @@ -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"), @@ -628,6 +656,27 @@ fn actual_multiply(left: Number, right: Number, swapped: bool) -> Result 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()); @@ -712,6 +761,12 @@ pub fn divide(left: Number, right: Number) -> Result { 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()); @@ -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);