From 709d0fac7ca974c030ac4dd2e33169dc3544e326 Mon Sep 17 00:00:00 2001 From: Angelica Schell Date: Tue, 6 Aug 2024 06:42:07 -0600 Subject: [PATCH 01/15] Intermediate Representation functions added and are now default. Will only try fast track with inputs less than FAST_TRACK_THRESHOLD number of bits, currently 24. --- tools/data-conversion/src/main.rs | 358 +++++++++++++++++++++++++++++- 1 file changed, 347 insertions(+), 11 deletions(-) diff --git a/tools/data-conversion/src/main.rs b/tools/data-conversion/src/main.rs index f41315a257..1e64b0f39d 100644 --- a/tools/data-conversion/src/main.rs +++ b/tools/data-conversion/src/main.rs @@ -1,5 +1,10 @@ //use std::env; use argh::FromArgs; +// use core::num; +use num_bigint::BigInt; +use num_bigint::BigUint; +// use num_traits::sign; +use num_traits::Num; use std::error::Error; use std::fmt; use std::fs::read_to_string; @@ -7,9 +12,17 @@ use std::fs::File; use std::io::stdout; use std::io::{self, Write}; use std::str::FromStr; - //cargo run -- --from $PATH1 --to $PATH2 --ftype "from" --totype "to" +// Threshold for using fast-track functions +const FAST_TRACK_THRESHOLD: u32 = 1 << 24; // Example threshold value, adjust as needed + +struct IntermediateRepresentation { + sign: bool, + mantissa: BigUint, + exponent: i32, +} + #[derive(Debug)] struct ParseNumTypeError; @@ -80,6 +93,7 @@ struct Arguments { /// optional for fixed_to_binary using bit slicing. If choosen, will use bit slicing. #[argh(switch, short = 'b')] bits: bool, + // optional switch for } fn main() { @@ -128,44 +142,108 @@ fn convert( match (convert_from, convert_to) { (NumType::Hex, NumType::Binary) => { for line in read_to_string(filepath_get).unwrap().lines() { - hex_to_binary(line, &mut converted) + if line.parse::().unwrap() <= FAST_TRACK_THRESHOLD as f32 { + hex_to_binary(line, &mut converted) + .expect("Failed to write binary to file"); + } else { + intermediate_to_binary( + hex_to_intermediate(line), + &mut converted, + ) .expect("Failed to write binary to file"); + } } } (NumType::Float, NumType::Binary) => { for line in read_to_string(filepath_get).unwrap().lines() { - float_to_binary(line, &mut converted) + if line.parse::().unwrap() <= FAST_TRACK_THRESHOLD as f32 { + float_to_binary(line, &mut converted) + .expect("Failed to write binary to file"); + } else { + intermediate_to_binary( + float_to_intermediate(line), + &mut converted, + ) .expect("Failed to write binary to file"); + } } } (NumType::Fixed, NumType::Binary) => { for line in read_to_string(filepath_get).unwrap().lines() { - fixed_to_binary(line, &mut converted, exponent) + if line.parse::().unwrap() <= FAST_TRACK_THRESHOLD as f32 { + fixed_to_binary(line, &mut converted, exponent) + .expect("Failed to write binary to file"); + } else { + intermediate_to_binary( + fixed_to_intermediate(line, exponent), + &mut converted, + ) .expect("Failed to write binary to file"); + } } } (NumType::Binary, NumType::Hex) => { for line in read_to_string(filepath_get).unwrap().lines() { - binary_to_hex(line, &mut converted) - .expect("Failed to write hex to file"); + if line.parse::().unwrap() <= FAST_TRACK_THRESHOLD as f32 { + binary_to_hex(line, &mut converted) + .expect("Failed to write hex to file"); + } else { + intermediate_to_hex( + binary_to_intermediate(line), + &mut converted, + ) + .expect("Failed to write binary to file"); + } } } (NumType::Binary, NumType::Float) => { for line in read_to_string(filepath_get).unwrap().lines() { - binary_to_float(line, &mut converted) - .expect("Failed to write float to file"); + if line.parse::().unwrap() <= FAST_TRACK_THRESHOLD as f32 { + binary_to_float(line, &mut converted) + .expect("Failed to write float to file"); + } else { + intermediate_to_float( + binary_to_intermediate(line), + &mut converted, + ) + .expect("Failed to write binary to file"); + } } } (NumType::Binary, NumType::Fixed) => { if !bits { for line in read_to_string(filepath_get).unwrap().lines() { - binary_to_fixed(line, &mut converted, exponent) - .expect("Failed to write fixed-point to file"); + if line.parse::().unwrap() + <= FAST_TRACK_THRESHOLD as f32 + { + binary_to_fixed(line, &mut converted, exponent) + .expect("Failed to write fixed-point to file"); + } else { + intermediate_to_fixed( + binary_to_intermediate(line), + &mut converted, + ) + .expect("Failed to write binary to file"); + } } } else { for line in read_to_string(filepath_get).unwrap().lines() { - binary_to_fixed_bit_slice(line, &mut converted, exponent) + if line.parse::().unwrap() + <= FAST_TRACK_THRESHOLD as f32 + { + binary_to_fixed_bit_slice( + line, + &mut converted, + exponent, + ) .expect("Failed to write fixed-point to file"); + } else { + intermediate_to_fixed( + binary_to_intermediate(line), + &mut converted, + ) + .expect("Failed to write binary to file"); + } } } } @@ -549,3 +627,261 @@ fn binary_to_fixed_bit_slice( Ok(()) } + +fn binary_to_intermediate(binary_string: &str) -> IntermediateRepresentation { + let bit_width = binary_string.len(); + + let sign = binary_string.chars().next() == Some('0'); + + let binary_value = BigUint::from_str_radix(binary_string, 2) + .expect("Invalid binary string"); + + let mantissa = if sign { + binary_value + } else { + // Calculate the two's complement for negative values + let max_value = BigUint::from(1u32) << bit_width; + &max_value - &binary_value + }; + + IntermediateRepresentation { + sign, + mantissa, + exponent: 0, + } +} + +fn intermediate_to_binary( + inter_rep: IntermediateRepresentation, + filepath_send: &mut Option, +) -> io::Result<()> { + let inter_value = if inter_rep.sign { + BigInt::from(inter_rep.mantissa) + } else { + -BigInt::from(inter_rep.mantissa) + }; + + let binary_str = inter_value.to_str_radix(2); + + if let Some(file) = filepath_send { + file.write_all(binary_str.as_bytes())?; + file.write_all(b"\n")?; + } else { + std::io::stdout().write_all(binary_str.as_bytes())?; + std::io::stdout().write_all(b"\n")?; + } + + Ok(()) +} + +fn float_to_intermediate(float_string: &str) -> IntermediateRepresentation { + let sign = !float_string.starts_with("-"); + let float_trimmed = float_string.trim_start_matches("-"); + + let parts: Vec<&str> = float_trimmed.split('.').collect(); + let integer_part = parts[0]; + let fractional_part = if parts.len() > 1 { parts[1] } else { "0" }; + // Prob not the best way to do this + let mantissa_string = format!("{integer_part}{fractional_part}"); + + IntermediateRepresentation { + sign, + mantissa: BigUint::from_str(&mantissa_string).expect("Invalid number"), + exponent: -(fractional_part.len() as i32), + } +} + +fn intermediate_to_float( + inter_rep: IntermediateRepresentation, + filepath_send: &mut Option, +) -> io::Result<()> { + let mut mantissa_str = inter_rep.mantissa.to_string(); + + // Determine the position to insert the decimal point + let mut decimal_pos = mantissa_str.len() as i32 - inter_rep.exponent; + + // Handle cases where the decimal position is before the first digit + if decimal_pos <= 0 { + let zero_padding = "0".repeat(-decimal_pos as usize); + mantissa_str = format!("{}{}", zero_padding, mantissa_str); + decimal_pos = 1; // Decimal point will be at the first digit position + } + + // Convert to &str for split_at + let mantissa_str = mantissa_str.as_str(); + + // Insert the decimal point + let decimal_position = decimal_pos as usize; + let (integer_part, fractional_part) = if decimal_position > 0 { + mantissa_str.split_at(decimal_position) + } else { + ("0", mantissa_str) + }; + + let result = if inter_rep.sign { + format!("{}.{}", integer_part, fractional_part) + } else { + format!("-{}.{}", integer_part, fractional_part) + }; + + if let Some(file) = filepath_send.as_mut() { + // Write string to the file + file.write_all(result.as_bytes())?; + file.write_all(b"\n")?; + } else { + io::stdout().write_all(result.as_bytes())?; + io::stdout().write_all(b"\n")?; + } + + Ok(()) +} + +fn fixed_to_intermediate( + fixed_string: &str, + exp_int: i32, +) -> IntermediateRepresentation { + let sign = !fixed_string.starts_with("-"); + let fixed_trimmed = fixed_string.trim_start_matches("-"); + + let mantissa_string = &format!("{fixed_trimmed}"); + + IntermediateRepresentation { + sign, + mantissa: BigUint::from_str(mantissa_string).expect("Invalid number"), + exponent: exp_int, + } +} + +fn intermediate_to_fixed( + inter_rep: IntermediateRepresentation, + filepath_send: &mut Option, +) -> io::Result<()> { + // Negate exp + let neg_exponent = -inter_rep.exponent; + + // 10^-exp + let scale_factor = BigInt::from(10).pow(neg_exponent as u32); + + // Convert mantissa to BigInt + let mantissa_bigint = BigInt::from(inter_rep.mantissa); + + let mantissa_mult = mantissa_bigint * scale_factor; + + // Apply the sign + let signed_value = if inter_rep.sign { + mantissa_mult + } else { + -mantissa_mult + }; + + // Handle placement of decimal point + let mantissa_str = signed_value.to_string(); + let mantissa_len = mantissa_str.len(); + let adjusted_exponent = inter_rep.exponent + mantissa_len as i32; + + let string = if adjusted_exponent <= 0 { + // Handle case where the exponent indicates a number less than 1 + let zero_padding = "0".repeat(-adjusted_exponent as usize); + format!("0.{}{}", zero_padding, mantissa_str) + } else if adjusted_exponent as usize >= mantissa_len { + // Handle case where the exponent is larger than the length of the mantissa + format!( + "{}{}", + mantissa_str, + "0".repeat(adjusted_exponent as usize - mantissa_len) + ) + } else { + // Normal case + let integer_part = &mantissa_str[..adjusted_exponent as usize]; + let fractional_part = &mantissa_str[adjusted_exponent as usize..]; + format!("{}.{}", integer_part, fractional_part) + }; + + // Write the result to the file or stdout + if let Some(file) = filepath_send.as_mut() { + file.write_all(string.as_bytes())?; + file.write_all(b"\n")?; + } else { + io::stdout().write_all(string.as_bytes())?; + io::stdout().write_all(b"\n")?; + } + + Ok(()) +} + +fn hex_to_intermediate(hex_string: &str) -> IntermediateRepresentation { + // Get sign value before converting string + let sign = hex_string.chars().next() != Some('-'); + + // Remove the '-' sign if present + let cleaned_hex_string = if sign { hex_string } else { &hex_string[1..] }; + + // Convert the cleaned hexadecimal string to BigUint + let hex_value = BigUint::from_str_radix(cleaned_hex_string, 16) + .expect("Invalid hexadecimal string"); + + IntermediateRepresentation { + sign, + mantissa: hex_value, + exponent: 0, + } +} + +fn intermediate_to_hex( + inter_rep: IntermediateRepresentation, + filepath_send: &mut Option, +) -> io::Result<()> { + // Apply the sign + let hex_value = if inter_rep.sign { + inter_rep.mantissa.to_str_radix(16) + } else { + format!("-{}", inter_rep.mantissa.to_str_radix(16)) + }; + + // Write the result to the file or stdout + if let Some(file) = filepath_send.as_mut() { + file.write_all(hex_value.as_bytes())?; + file.write_all(b"\n")?; + } else { + io::stdout().write_all(hex_value.as_bytes())?; + io::stdout().write_all(b"\n")?; + } + + Ok(()) +} + +// ChatGPT stuff below + +// fn format_scientific_notation(num_str: &str, exponent: i32) -> String { +// // Check for an empty string +// if num_str.is_empty() { +// return "0.0e0".to_string(); +// } + +// // Find the position of the decimal point +// let (integer_part, fractional_part) = if num_str.contains('.') { +// let parts: Vec<&str> = num_str.split('.').collect(); +// (parts[0], parts.get(1).unwrap_or(&"")) +// } else { +// (num_str, "") +// }; + +// // Calculate the new exponent after including the fractional part +// let new_exponent = exponent + integer_part.len() as i32; + +// // Format integer part and fractional part +// let integer_part = integer_part.to_string(); +// let mut fractional_part = fractional_part.to_string(); +// let mut result = String::new(); + +// if !integer_part.is_empty() { +// result.push_str(&integer_part); +// } + +// if !fractional_part.is_empty() { +// result.push('.'); +// result.push_str(&fractional_part); +// } + +// format!("{:+.8e}", result.to_f64().unwrap_or(0.0)) // Converting to f64 for formatting +// } From 51f4ee86473ca16ec808c5e26b9c131575e33382 Mon Sep 17 00:00:00 2001 From: Angelica Schell Date: Tue, 6 Aug 2024 06:45:54 -0600 Subject: [PATCH 02/15] Addded some dependencies --- tools/data-conversion/Cargo.toml | 3 ++- tools/data-conversion/src/main.rs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/data-conversion/Cargo.toml b/tools/data-conversion/Cargo.toml index 87bdf6fd3c..be2f704ed5 100644 --- a/tools/data-conversion/Cargo.toml +++ b/tools/data-conversion/Cargo.toml @@ -16,4 +16,5 @@ rust-version.workspace = true [dependencies] argh.workspace = true - +num-bigint = { version = "0.4", workspace = true } +num-traits = { version = "0.2", workspace = true } \ No newline at end of file diff --git a/tools/data-conversion/src/main.rs b/tools/data-conversion/src/main.rs index 1e64b0f39d..7e8e769cc2 100644 --- a/tools/data-conversion/src/main.rs +++ b/tools/data-conversion/src/main.rs @@ -15,7 +15,7 @@ use std::str::FromStr; //cargo run -- --from $PATH1 --to $PATH2 --ftype "from" --totype "to" // Threshold for using fast-track functions -const FAST_TRACK_THRESHOLD: u32 = 1 << 24; // Example threshold value, adjust as needed +const FAST_TRACK_THRESHOLD: u32 = 1 << 24; struct IntermediateRepresentation { sign: bool, From ab020742875c956d6bc97ef5464317c63879ae13 Mon Sep 17 00:00:00 2001 From: Angelica Schell Date: Wed, 7 Aug 2024 22:17:24 -0600 Subject: [PATCH 03/15] Added spec for intermediate representation functions --- tools/data-conversion/src/main.rs | 189 ++++++++++++++++++++++++------ 1 file changed, 152 insertions(+), 37 deletions(-) diff --git a/tools/data-conversion/src/main.rs b/tools/data-conversion/src/main.rs index 7e8e769cc2..80b8c3fdfa 100644 --- a/tools/data-conversion/src/main.rs +++ b/tools/data-conversion/src/main.rs @@ -628,6 +628,26 @@ fn binary_to_fixed_bit_slice( Ok(()) } + +/// Converts a string representation of a binary number the intermediate representation. +/// +/// This function takes a string slice representing a binary number, +/// converts it to a `BigUint`, determines the sign, and constructs an +/// `IntermediateRepresentation` containing the sign, mantissa, and exponent. +/// +/// # Arguments +/// +/// * `binary_string` - A string slice containing the binary number to be converted. +/// +/// # Returns +/// +/// This function returns an `IntermediateRepresentation` containing the sign, mantissa, +/// and exponent of the binary number. +/// +/// # Panics +/// +/// This function will panic if the input string cannot be parsed as a binary number. + fn binary_to_intermediate(binary_string: &str) -> IntermediateRepresentation { let bit_width = binary_string.len(); @@ -651,6 +671,24 @@ fn binary_to_intermediate(binary_string: &str) -> IntermediateRepresentation { } } + +/// Converts the intermediate representation to a binary string and writes it to a file or stdout. +/// +/// This function takes an `IntermediateRepresentation`, converts the mantissa to a `BigInt` +/// applying the sign, converts the resulting `BigInt` to a binary string, and writes +/// the binary string to the specified file or stdout. +/// +/// # Arguments +/// +/// * `inter_rep` - The intermediate representation to be converted. +/// * `filepath_send` - A mutable reference to an optional `File` where the binary string +/// will be written. If `None`, the result is written to stdout. +/// +/// # Returns +/// +/// This function returns a `std::io::Result<()>` which is `Ok` if the operation +/// is successful, or an `Err` if an I/O error occurs while writing to the file. + fn intermediate_to_binary( inter_rep: IntermediateRepresentation, filepath_send: &mut Option, @@ -674,6 +712,26 @@ fn intermediate_to_binary( Ok(()) } + +/// Converts a string representation of a floating-point number to the intermediate representation. +/// +/// This function takes a string slice representing a floating-point number, +/// splits it into integer and fractional parts, constructs the mantissa, +/// sets the exponent based on the length of the fractional part, and +/// constructs an `IntermediateRepresentation` containing the sign, mantissa, and exponent. +/// +/// # Arguments +/// +/// * `float_string` - A string slice containing the floating-point number to be converted. +/// +/// # Returns +/// +/// This function returns an `IntermediateRepresentation` containing the sign, mantissa, +/// and exponent of the floating-point number. +/// +/// # Panics +/// +/// This function will panic if the input string cannot be parsed as a number. fn float_to_intermediate(float_string: &str) -> IntermediateRepresentation { let sign = !float_string.starts_with("-"); let float_trimmed = float_string.trim_start_matches("-"); @@ -691,6 +749,25 @@ fn float_to_intermediate(float_string: &str) -> IntermediateRepresentation { } } + +/// Converts the intermediate representation to a floating-point number string and writes it to a file or stdout. +/// +/// This function takes an `IntermediateRepresentation`, converts the mantissa to a string, +/// inserts the decimal point at the correct position based on the exponent, constructs +/// the floating-point number string applying the sign, and writes the resulting string +/// to the specified file or stdout. +/// +/// # Arguments +/// +/// * `inter_rep` - The intermediate representation to be converted. +/// * `filepath_send` - A mutable reference to an optional `File` where the floating-point +/// number string will be written. If `None`, the result is written to stdout. +/// +/// # Returns +/// +/// This function returns a `std::io::Result<()>` which is `Ok` if the operation +/// is successful, or an `Err` if an I/O error occurs while writing to the file. + fn intermediate_to_float( inter_rep: IntermediateRepresentation, filepath_send: &mut Option, @@ -736,6 +813,26 @@ fn intermediate_to_float( Ok(()) } + +/// Converts a string representation of a fixed-point number to the intermediate representation. +/// +/// This function takes a string slice representing a fixed-point number and an exponent value, +/// determines the sign, constructs the mantissa, sets the exponent to the given value, and +/// constructs an `IntermediateRepresentation` containing the sign, mantissa, and exponent. +/// +/// # Arguments +/// +/// * `fixed_string` - A string slice containing the fixed-point number to be converted. +/// * `exp_int` - The exponent value for the fixed-point number. +/// +/// # Returns +/// +/// This function returns an `IntermediateRepresentation` containing the sign, mantissa, +/// and exponent of the fixed-point number. +/// +/// # Panics +/// +/// This function will panic if the input string cannot be parsed as a number. fn fixed_to_intermediate( fixed_string: &str, exp_int: i32, @@ -752,6 +849,24 @@ fn fixed_to_intermediate( } } + +/// Converts the intermediate representation to a fixed-point number string and writes it to a file or stdout. +/// +/// This function takes an `IntermediateRepresentation`, computes the scale factor based on +/// the negative exponent, converts the mantissa to a `BigInt` and multiplies by the scale factor, +/// constructs the fixed-point number string applying the sign, and writes the resulting string +/// to the specified file or stdout. +/// +/// # Arguments +/// +/// * `inter_rep` - The intermediate representation to be converted. +/// * `filepath_send` - A mutable reference to an optional `File` where the fixed-point +/// number string will be written. If `None`, the result is written to stdout. +/// +/// # Returns +/// +/// This function returns a `std::io::Result<()>` which is `Ok` if the operation +/// is successful, or an `Err` if an I/O error occurs while writing to the file. fn intermediate_to_fixed( inter_rep: IntermediateRepresentation, filepath_send: &mut Option, @@ -809,6 +924,26 @@ fn intermediate_to_fixed( Ok(()) } + +/// Converts a string representation of a hexadecimal number to the intermediate representation. +/// +/// This function takes a string slice representing a hexadecimal number, +/// converts it to a `BigUint`, determines the sign, and constructs an +/// `IntermediateRepresentation` containing the sign, mantissa, and exponent. +/// +/// # Arguments +/// +/// * `hex_string` - A string slice containing the hexadecimal number to be converted. +/// +/// # Returns +/// +/// This function returns an `IntermediateRepresentation` containing the sign, mantissa, +/// and exponent of the hexadecimal number. +/// +/// # Panics +/// +/// This function will panic if the input string cannot be parsed as a hexadecimal number. + fn hex_to_intermediate(hex_string: &str) -> IntermediateRepresentation { // Get sign value before converting string let sign = hex_string.chars().next() != Some('-'); @@ -827,6 +962,22 @@ fn hex_to_intermediate(hex_string: &str) -> IntermediateRepresentation { } } +/// Converts the intermediate representation to a hexadecimal string and writes it to a file or stdout. +/// +/// This function takes an `IntermediateRepresentation`, converts the mantissa to a hexadecimal string, +/// applies the sign, and writes the resulting string to the specified file or stdout. +/// +/// # Arguments +/// +/// * `inter_rep` - The intermediate representation to be converted. +/// * `filepath_send` - A mutable reference to an optional `File` where the hexadecimal string +/// will be written. If `None`, the result is written to stdout. +/// +/// # Returns +/// +/// This function returns a `std::io::Result<()>` which is `Ok` if the operation +/// is successful, or an `Err` if an I/O error occurs while writing to the file. + fn intermediate_to_hex( inter_rep: IntermediateRepresentation, filepath_send: &mut Option, @@ -848,40 +999,4 @@ fn intermediate_to_hex( } Ok(()) -} - -// ChatGPT stuff below - -// fn format_scientific_notation(num_str: &str, exponent: i32) -> String { -// // Check for an empty string -// if num_str.is_empty() { -// return "0.0e0".to_string(); -// } - -// // Find the position of the decimal point -// let (integer_part, fractional_part) = if num_str.contains('.') { -// let parts: Vec<&str> = num_str.split('.').collect(); -// (parts[0], parts.get(1).unwrap_or(&"")) -// } else { -// (num_str, "") -// }; - -// // Calculate the new exponent after including the fractional part -// let new_exponent = exponent + integer_part.len() as i32; - -// // Format integer part and fractional part -// let integer_part = integer_part.to_string(); -// let mut fractional_part = fractional_part.to_string(); -// let mut result = String::new(); - -// if !integer_part.is_empty() { -// result.push_str(&integer_part); -// } - -// if !fractional_part.is_empty() { -// result.push('.'); -// result.push_str(&fractional_part); -// } - -// format!("{:+.8e}", result.to_f64().unwrap_or(0.0)) // Converting to f64 for formatting -// } +} \ No newline at end of file From c71eb923f017cff5bd69849784877538f216eb0d Mon Sep 17 00:00:00 2001 From: Angelica Schell Date: Wed, 7 Aug 2024 22:24:25 -0600 Subject: [PATCH 04/15] formatting --- tools/data-conversion/src/main.rs | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/tools/data-conversion/src/main.rs b/tools/data-conversion/src/main.rs index 80b8c3fdfa..d372990009 100644 --- a/tools/data-conversion/src/main.rs +++ b/tools/data-conversion/src/main.rs @@ -15,7 +15,7 @@ use std::str::FromStr; //cargo run -- --from $PATH1 --to $PATH2 --ftype "from" --totype "to" // Threshold for using fast-track functions -const FAST_TRACK_THRESHOLD: u32 = 1 << 24; +const FAST_TRACK_THRESHOLD: u32 = 1 << 24; struct IntermediateRepresentation { sign: bool, @@ -628,7 +628,6 @@ fn binary_to_fixed_bit_slice( Ok(()) } - /// Converts a string representation of a binary number the intermediate representation. /// /// This function takes a string slice representing a binary number, @@ -651,7 +650,7 @@ fn binary_to_fixed_bit_slice( fn binary_to_intermediate(binary_string: &str) -> IntermediateRepresentation { let bit_width = binary_string.len(); - let sign = binary_string.chars().next() == Some('0'); + let sign = binary_string.starts_with('0'); let binary_value = BigUint::from_str_radix(binary_string, 2) .expect("Invalid binary string"); @@ -671,7 +670,6 @@ fn binary_to_intermediate(binary_string: &str) -> IntermediateRepresentation { } } - /// Converts the intermediate representation to a binary string and writes it to a file or stdout. /// /// This function takes an `IntermediateRepresentation`, converts the mantissa to a `BigInt` @@ -712,7 +710,6 @@ fn intermediate_to_binary( Ok(()) } - /// Converts a string representation of a floating-point number to the intermediate representation. /// /// This function takes a string slice representing a floating-point number, @@ -733,8 +730,8 @@ fn intermediate_to_binary( /// /// This function will panic if the input string cannot be parsed as a number. fn float_to_intermediate(float_string: &str) -> IntermediateRepresentation { - let sign = !float_string.starts_with("-"); - let float_trimmed = float_string.trim_start_matches("-"); + let sign = !float_string.starts_with('-'); + let float_trimmed = float_string.trim_start_matches('-'); let parts: Vec<&str> = float_trimmed.split('.').collect(); let integer_part = parts[0]; @@ -749,7 +746,6 @@ fn float_to_intermediate(float_string: &str) -> IntermediateRepresentation { } } - /// Converts the intermediate representation to a floating-point number string and writes it to a file or stdout. /// /// This function takes an `IntermediateRepresentation`, converts the mantissa to a string, @@ -813,7 +809,6 @@ fn intermediate_to_float( Ok(()) } - /// Converts a string representation of a fixed-point number to the intermediate representation. /// /// This function takes a string slice representing a fixed-point number and an exponent value, @@ -837,8 +832,8 @@ fn fixed_to_intermediate( fixed_string: &str, exp_int: i32, ) -> IntermediateRepresentation { - let sign = !fixed_string.starts_with("-"); - let fixed_trimmed = fixed_string.trim_start_matches("-"); + let sign = !fixed_string.starts_with('-'); + let fixed_trimmed = fixed_string.trim_start_matches('-'); let mantissa_string = &format!("{fixed_trimmed}"); @@ -849,7 +844,6 @@ fn fixed_to_intermediate( } } - /// Converts the intermediate representation to a fixed-point number string and writes it to a file or stdout. /// /// This function takes an `IntermediateRepresentation`, computes the scale factor based on @@ -924,7 +918,6 @@ fn intermediate_to_fixed( Ok(()) } - /// Converts a string representation of a hexadecimal number to the intermediate representation. /// /// This function takes a string slice representing a hexadecimal number, @@ -946,7 +939,7 @@ fn intermediate_to_fixed( fn hex_to_intermediate(hex_string: &str) -> IntermediateRepresentation { // Get sign value before converting string - let sign = hex_string.chars().next() != Some('-'); + let sign = !hex_string.starts_with('-'); // Remove the '-' sign if present let cleaned_hex_string = if sign { hex_string } else { &hex_string[1..] }; @@ -999,4 +992,4 @@ fn intermediate_to_hex( } Ok(()) -} \ No newline at end of file +} From c317b635d32529c652a816ba17ef534255578247 Mon Sep 17 00:00:00 2001 From: Angelica Schell Date: Thu, 8 Aug 2024 07:52:09 -0600 Subject: [PATCH 05/15] fixed dependencies --- tools/data-conversion/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/data-conversion/Cargo.toml b/tools/data-conversion/Cargo.toml index be2f704ed5..d4ea846c7a 100644 --- a/tools/data-conversion/Cargo.toml +++ b/tools/data-conversion/Cargo.toml @@ -16,5 +16,5 @@ rust-version.workspace = true [dependencies] argh.workspace = true -num-bigint = { version = "0.4", workspace = true } -num-traits = { version = "0.2", workspace = true } \ No newline at end of file +num-bigint = "0.4" +num-traits = "0.2" \ No newline at end of file From a134703ad19e4978f7e8bba5dbc13128b8e99260 Mon Sep 17 00:00:00 2001 From: Angelica Schell Date: Fri, 9 Aug 2024 09:07:33 -0600 Subject: [PATCH 06/15] Updated from 32 bit width to 64 --- tools/data-conversion/src/main.rs | 108 +++++++++++++++--------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/tools/data-conversion/src/main.rs b/tools/data-conversion/src/main.rs index d372990009..da1f51277f 100644 --- a/tools/data-conversion/src/main.rs +++ b/tools/data-conversion/src/main.rs @@ -15,12 +15,12 @@ use std::str::FromStr; //cargo run -- --from $PATH1 --to $PATH2 --ftype "from" --totype "to" // Threshold for using fast-track functions -const FAST_TRACK_THRESHOLD: u32 = 1 << 24; +const FAST_TRACK_THRESHOLD: u64 = 1 << 24; struct IntermediateRepresentation { sign: bool, mantissa: BigUint, - exponent: i32, + exponent: i64, } #[derive(Debug)] @@ -88,7 +88,7 @@ struct Arguments { /// optional exponent for fixed_to_binary -> default is -1 #[argh(option, default = "-1")] - exp: i32, + exp: i64, /// optional for fixed_to_binary using bit slicing. If choosen, will use bit slicing. #[argh(switch, short = 'b')] @@ -120,7 +120,7 @@ fn main() { /// where the converted data will be written. /// * `convert_from` - A reference to a `NumType` enum indicating the type of the input data. /// * `convert_to` - A reference to a `NumType` enum indicating the type of the output data. -/// * `exponent` - An `i32` value used as the exponent for conversions involving fixed-point numbers. +/// * `exponent` - An `i64` value used as the exponent for conversions involving fixed-point numbers. /// /// # Returns /// @@ -131,7 +131,7 @@ fn convert( filepath_send: &Option, convert_from: NumType, convert_to: NumType, - exponent: i32, + exponent: i64, bits: bool, ) { // Create the output file if filepath_send is Some @@ -142,7 +142,7 @@ fn convert( match (convert_from, convert_to) { (NumType::Hex, NumType::Binary) => { for line in read_to_string(filepath_get).unwrap().lines() { - if line.parse::().unwrap() <= FAST_TRACK_THRESHOLD as f32 { + if line.parse::().unwrap() <= FAST_TRACK_THRESHOLD as f64 { hex_to_binary(line, &mut converted) .expect("Failed to write binary to file"); } else { @@ -156,7 +156,7 @@ fn convert( } (NumType::Float, NumType::Binary) => { for line in read_to_string(filepath_get).unwrap().lines() { - if line.parse::().unwrap() <= FAST_TRACK_THRESHOLD as f32 { + if line.parse::().unwrap() <= FAST_TRACK_THRESHOLD as f64 { float_to_binary(line, &mut converted) .expect("Failed to write binary to file"); } else { @@ -170,7 +170,7 @@ fn convert( } (NumType::Fixed, NumType::Binary) => { for line in read_to_string(filepath_get).unwrap().lines() { - if line.parse::().unwrap() <= FAST_TRACK_THRESHOLD as f32 { + if line.parse::().unwrap() <= FAST_TRACK_THRESHOLD as f64 { fixed_to_binary(line, &mut converted, exponent) .expect("Failed to write binary to file"); } else { @@ -184,7 +184,7 @@ fn convert( } (NumType::Binary, NumType::Hex) => { for line in read_to_string(filepath_get).unwrap().lines() { - if line.parse::().unwrap() <= FAST_TRACK_THRESHOLD as f32 { + if line.parse::().unwrap() <= FAST_TRACK_THRESHOLD as f64 { binary_to_hex(line, &mut converted) .expect("Failed to write hex to file"); } else { @@ -198,7 +198,7 @@ fn convert( } (NumType::Binary, NumType::Float) => { for line in read_to_string(filepath_get).unwrap().lines() { - if line.parse::().unwrap() <= FAST_TRACK_THRESHOLD as f32 { + if line.parse::().unwrap() <= FAST_TRACK_THRESHOLD as f64 { binary_to_float(line, &mut converted) .expect("Failed to write float to file"); } else { @@ -213,8 +213,8 @@ fn convert( (NumType::Binary, NumType::Fixed) => { if !bits { for line in read_to_string(filepath_get).unwrap().lines() { - if line.parse::().unwrap() - <= FAST_TRACK_THRESHOLD as f32 + if line.parse::().unwrap() + <= FAST_TRACK_THRESHOLD as f64 { binary_to_fixed(line, &mut converted, exponent) .expect("Failed to write fixed-point to file"); @@ -228,8 +228,8 @@ fn convert( } } else { for line in read_to_string(filepath_get).unwrap().lines() { - if line.parse::().unwrap() - <= FAST_TRACK_THRESHOLD as f32 + if line.parse::().unwrap() + <= FAST_TRACK_THRESHOLD as f64 { binary_to_fixed_bit_slice( line, @@ -270,8 +270,8 @@ fn convert( } /// Formats [to_format] properly for float values -fn format_binary(to_format: u32) -> String { - let binary_str = format!("{:032b}", to_format); +fn format_binary(to_format: u64) -> String { + let binary_str = format!("{:064b}", to_format); format!( "{} {} {}", &binary_str[0..1], // Sign bit @@ -280,7 +280,7 @@ fn format_binary(to_format: u32) -> String { ) } -fn format_hex(to_format: u32) -> String { +fn format_hex(to_format: u64) -> String { format!("0x{:X}", to_format) } @@ -288,7 +288,7 @@ fn format_hex(to_format: u32) -> String { /// format and appends the result to the specified file. /// /// This function takes a string slice representing a floating-point number, -/// converts it to a 32-bit floating-point number (`f32`), then converts this +/// converts it to a 64-bit floating-point number (`f64`), then converts this /// number to its binary representation. The binary representation is formatted /// as a string and written to the specified file, followed by a newline. /// @@ -310,9 +310,9 @@ fn float_to_binary( float_string: &str, filepath_send: &mut Option, ) -> std::io::Result<()> { - let float_of_string: f32; + let float_of_string: f64; // Convert string to float - match float_string.parse::() { + match float_string.parse::() { Ok(parsed_num) => float_of_string = parsed_num, Err(_) => { panic!("Failed to parse float from string") @@ -338,7 +338,7 @@ fn float_to_binary( /// format and appends the result to the specified file. /// /// This function takes a string slice representing a hexadecimal number, -/// converts it to a 32-bit integer (`u32`), then converts this number to its +/// converts it to a 64-bit integer (`u64`), then converts this number to its /// binary representation. The binary representation is formatted as a string /// and written to the specified file, followed by a newline. /// @@ -361,7 +361,7 @@ fn hex_to_binary( filepath_send: &mut Option, ) -> io::Result<()> { // Convert hex to binary - let binary_of_hex = u32::from_str_radix(hex_string, 16) + let binary_of_hex = u64::from_str_radix(hex_string, 16) .expect("Failed to parse hex string"); // Format nicely @@ -385,7 +385,7 @@ fn hex_to_binary( /// format and appends the result to the specified file. /// /// This function takes a string slice representing a binary number, -/// converts it to a 32-bit integer (`u32`), then converts this number to its +/// converts it to a 64-bit integer (`u64`), then converts this number to its /// hexadecimal representation. The hexadecimal representation is formatted /// as a string and written to the specified file, followed by a newline. /// @@ -407,7 +407,7 @@ fn binary_to_hex( binary_string: &str, filepath_send: &mut Option, ) -> io::Result<()> { - let hex_of_binary = u32::from_str_radix(binary_string, 2) + let hex_of_binary = u64::from_str_radix(binary_string, 2) .expect("Failed to parse binary string"); let formatted_hex_str = format_hex(hex_of_binary); @@ -428,8 +428,8 @@ fn binary_to_hex( /// format and appends the result to the specified file. /// /// This function takes a string slice representing a binary number, -/// converts it to a 32-bit integer (`u32`), then interprets this integer as -/// the binary representation of a 32-bit floating-point number (`f32`). +/// converts it to a 64-bit integer (`u64`), then interprets this integer as +/// the binary representation of a 64-bit floating-point number (`f64`). /// The floating-point representation is formatted as a string and written /// to the specified file, followed by a newline. /// @@ -451,11 +451,11 @@ fn binary_to_float( binary_string: &str, filepath_send: &mut Option, ) -> io::Result<()> { - let binary_value = u32::from_str_radix(binary_string, 2) + let binary_value = u64::from_str_radix(binary_string, 2) .expect("Failed to parse binary string"); // Interpret the integer as the binary representation of a floating-point number - let float_value = f32::from_bits(binary_value); + let float_value = f64::from_bits(binary_value); let formated_float_str = format!("{:?}", float_value); @@ -476,7 +476,7 @@ fn binary_to_float( /// /// This function takes a string slice representing a fixed-point number, /// multiplies it by 2 raised to the power of the negative exponent, converts the result -/// to a 32-bit integer, and then to its binary representation. The binary representation +/// to a 64-bit integer, and then to its binary representation. The binary representation /// is formatted as a string and written to the specified file, followed by a newline. /// /// # Arguments @@ -498,11 +498,11 @@ fn binary_to_float( fn fixed_to_binary( fixed_string: &str, filepath_send: &mut Option, - exp_int: i32, + exp_int: i64, ) -> io::Result<()> { // Convert fixed value from string to int - let fixed_value: f32; - match fixed_string.parse::() { + let fixed_value: f64; + match fixed_string.parse::() { Ok(parsed_num) => fixed_value = parsed_num, Err(_) => { panic!("Bad fixed value input") @@ -510,16 +510,16 @@ fn fixed_to_binary( } //exponent int to float so we can multiply - let exponent = exp_int as f32; + let exponent = exp_int as f64; // Exponent math - let multiplied_fixed = fixed_value * 2_f32.powf(-exponent); + let multiplied_fixed = fixed_value * 2_f64.powf(-exponent); - // Convert to a 32-bit integer - let multiplied_fixed_as_i32 = multiplied_fixed as i32; + // Convert to a 64-bit integer + let multiplied_fixed_as_i64 = multiplied_fixed as i64; - // Convert to a binary string with 32 bits - let binary_of_fixed = format!("{:032b}", multiplied_fixed_as_i32); + // Convert to a binary string with 64 bits + let binary_of_fixed = format!("{:064b}", multiplied_fixed_as_i64); if let Some(file) = filepath_send.as_mut() { // Write binary string to the file @@ -537,7 +537,7 @@ fn fixed_to_binary( /// format and appends the result to the specified file. /// /// This function takes a string slice representing a binary number, -/// converts it to a 32-bit unsigned integer, interprets this integer as +/// converts it to a 64-bit unsigned integer, interprets this integer as /// a floating-point number, divides it by 2 raised to the power of the negative exponent, /// and converts the result to its fixed-point representation. The fixed-point /// representation is formatted as a string and written to the specified file, @@ -562,22 +562,22 @@ fn fixed_to_binary( fn binary_to_fixed( binary_string: &str, filepath_send: &mut Option, - exp_int: i32, + exp_int: i64, ) -> io::Result<()> { // Convert binary value from string to int - let binary_value = match u32::from_str_radix(binary_string, 2) { + let binary_value = match u64::from_str_radix(binary_string, 2) { Ok(parsed_num) => parsed_num, Err(_) => panic!("Bad binary value input"), }; // Convert to fixed - let int_of_binary = binary_value as f32; + let int_of_binary = binary_value as f64; //exponent int to float so we can multiply - let exponent = exp_int as f32; + let exponent = exp_int as f64; // Exponent math - let divided: f32 = int_of_binary / 2_f32.powf(-exponent); + let divided: f64 = int_of_binary / 2_f64.powf(-exponent); let string_of_divided = format!("{:+.8e}", divided); @@ -596,23 +596,23 @@ fn binary_to_fixed( fn binary_to_fixed_bit_slice( binary_string: &str, filepath_send: &mut Option, - exp_int: i32, + exp_int: i64, ) -> io::Result<()> { // Convert binary string to an integer (assuming binary_string is a valid binary representation) - let binary_int = u32::from_str_radix(binary_string, 2).unwrap(); + let binary_int = u64::from_str_radix(binary_string, 2).unwrap(); // Adjust the binary point based on the exponent let mut result = binary_int; if exp_int < 0 { // If exponent is negative, shift right (multiply by 2^(-exp_int)) - result >>= -exp_int as u32; + result >>= -exp_int as u64; } else { // If exponent is positive, shift left (multiply by 2^(exp_int)) - result <<= exp_int as u32; + result <<= exp_int as u64; } // Convert result to a fixed-point decimal representation - let fixed_value = result as f32; + let fixed_value = result as f64; let string_of_fixed = format!("{:.8e}", fixed_value); @@ -659,7 +659,7 @@ fn binary_to_intermediate(binary_string: &str) -> IntermediateRepresentation { binary_value } else { // Calculate the two's complement for negative values - let max_value = BigUint::from(1u32) << bit_width; + let max_value = BigUint::from(1u64) << bit_width; &max_value - &binary_value }; @@ -742,7 +742,7 @@ fn float_to_intermediate(float_string: &str) -> IntermediateRepresentation { IntermediateRepresentation { sign, mantissa: BigUint::from_str(&mantissa_string).expect("Invalid number"), - exponent: -(fractional_part.len() as i32), + exponent: -(fractional_part.len() as i64), } } @@ -771,7 +771,7 @@ fn intermediate_to_float( let mut mantissa_str = inter_rep.mantissa.to_string(); // Determine the position to insert the decimal point - let mut decimal_pos = mantissa_str.len() as i32 - inter_rep.exponent; + let mut decimal_pos = mantissa_str.len() as i64 - inter_rep.exponent; // Handle cases where the decimal position is before the first digit if decimal_pos <= 0 { @@ -830,7 +830,7 @@ fn intermediate_to_float( /// This function will panic if the input string cannot be parsed as a number. fn fixed_to_intermediate( fixed_string: &str, - exp_int: i32, + exp_int: i64, ) -> IntermediateRepresentation { let sign = !fixed_string.starts_with('-'); let fixed_trimmed = fixed_string.trim_start_matches('-'); @@ -886,7 +886,7 @@ fn intermediate_to_fixed( // Handle placement of decimal point let mantissa_str = signed_value.to_string(); let mantissa_len = mantissa_str.len(); - let adjusted_exponent = inter_rep.exponent + mantissa_len as i32; + let adjusted_exponent = inter_rep.exponent + mantissa_len as i64; let string = if adjusted_exponent <= 0 { // Handle case where the exponent indicates a number less than 1 From cbd9d31e53e0bc868eefadd14ce354b8b76e1eda Mon Sep 17 00:00:00 2001 From: Angelica Schell Date: Fri, 9 Aug 2024 10:06:00 -0600 Subject: [PATCH 07/15] Updated thresholds and corrected error in using thresholds --- tools/data-conversion/src/main.rs | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/tools/data-conversion/src/main.rs b/tools/data-conversion/src/main.rs index da1f51277f..87a735ae17 100644 --- a/tools/data-conversion/src/main.rs +++ b/tools/data-conversion/src/main.rs @@ -14,8 +14,13 @@ use std::io::{self, Write}; use std::str::FromStr; //cargo run -- --from $PATH1 --to $PATH2 --ftype "from" --totype "to" -// Threshold for using fast-track functions -const FAST_TRACK_THRESHOLD: u64 = 1 << 24; +// Thresholds for using fast-track functions +const FAST_TRACK_THRESHOLD_BINARY_TO_FIXED: usize = 53; //52 bits for the significand (plus 1 implicit bit)b +const FAST_TRACK_THRESHOLD_FLOAT_TO_BINARY: usize = 53; +const FAST_TRACK_THRESHOLD_BINARY_TO_FLOAT: usize = 53; +const FAST_TRACK_THRESHOLD_FIXED_TO_BINARY: usize = 53; +const FAST_TRACK_THRESHOLD_HEX_TO_BINARY: usize = 64; +const FAST_TRACK_THRESHOLD_BINARY_TO_HEX: usize = 64; struct IntermediateRepresentation { sign: bool, @@ -34,7 +39,7 @@ impl fmt::Display for ParseNumTypeError { impl Error for ParseNumTypeError {} -#[derive(Debug, PartialEq, Clone, Copy)] // Add PartialEq derivation here - What is this? +#[derive(Debug, PartialEq, Clone, Copy)] // Add PartialEq derivation here enum NumType { Binary, Float, @@ -142,7 +147,7 @@ fn convert( match (convert_from, convert_to) { (NumType::Hex, NumType::Binary) => { for line in read_to_string(filepath_get).unwrap().lines() { - if line.parse::().unwrap() <= FAST_TRACK_THRESHOLD as f64 { + if line.len() <= FAST_TRACK_THRESHOLD_HEX_TO_BINARY { hex_to_binary(line, &mut converted) .expect("Failed to write binary to file"); } else { @@ -156,7 +161,7 @@ fn convert( } (NumType::Float, NumType::Binary) => { for line in read_to_string(filepath_get).unwrap().lines() { - if line.parse::().unwrap() <= FAST_TRACK_THRESHOLD as f64 { + if line.len() <= FAST_TRACK_THRESHOLD_FLOAT_TO_BINARY { float_to_binary(line, &mut converted) .expect("Failed to write binary to file"); } else { @@ -170,7 +175,7 @@ fn convert( } (NumType::Fixed, NumType::Binary) => { for line in read_to_string(filepath_get).unwrap().lines() { - if line.parse::().unwrap() <= FAST_TRACK_THRESHOLD as f64 { + if line.len() <= FAST_TRACK_THRESHOLD_FIXED_TO_BINARY { fixed_to_binary(line, &mut converted, exponent) .expect("Failed to write binary to file"); } else { @@ -184,10 +189,12 @@ fn convert( } (NumType::Binary, NumType::Hex) => { for line in read_to_string(filepath_get).unwrap().lines() { - if line.parse::().unwrap() <= FAST_TRACK_THRESHOLD as f64 { + print!("used fastpath"); + if line.len() <= FAST_TRACK_THRESHOLD_BINARY_TO_HEX { binary_to_hex(line, &mut converted) .expect("Failed to write hex to file"); } else { + print!("used intermediate"); intermediate_to_hex( binary_to_intermediate(line), &mut converted, @@ -198,7 +205,7 @@ fn convert( } (NumType::Binary, NumType::Float) => { for line in read_to_string(filepath_get).unwrap().lines() { - if line.parse::().unwrap() <= FAST_TRACK_THRESHOLD as f64 { + if line.len() <= FAST_TRACK_THRESHOLD_BINARY_TO_FLOAT { binary_to_float(line, &mut converted) .expect("Failed to write float to file"); } else { @@ -213,9 +220,7 @@ fn convert( (NumType::Binary, NumType::Fixed) => { if !bits { for line in read_to_string(filepath_get).unwrap().lines() { - if line.parse::().unwrap() - <= FAST_TRACK_THRESHOLD as f64 - { + if line.len() <= FAST_TRACK_THRESHOLD_BINARY_TO_FIXED { binary_to_fixed(line, &mut converted, exponent) .expect("Failed to write fixed-point to file"); } else { @@ -228,9 +233,7 @@ fn convert( } } else { for line in read_to_string(filepath_get).unwrap().lines() { - if line.parse::().unwrap() - <= FAST_TRACK_THRESHOLD as f64 - { + if line.len() <= FAST_TRACK_THRESHOLD_BINARY_TO_FIXED { binary_to_fixed_bit_slice( line, &mut converted, From eac7ba387ef3268fb5a37a9998d63a0100b6d5e1 Mon Sep 17 00:00:00 2001 From: Angelica Schell Date: Fri, 9 Aug 2024 22:39:53 -0600 Subject: [PATCH 08/15] updated intermediate rep functions into helper functions and implemented some other suggestions --- tools/data-conversion/src/main.rs | 49 ++++++++++++++++--------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/tools/data-conversion/src/main.rs b/tools/data-conversion/src/main.rs index 87a735ae17..2f244be6f7 100644 --- a/tools/data-conversion/src/main.rs +++ b/tools/data-conversion/src/main.rs @@ -22,6 +22,9 @@ const FAST_TRACK_THRESHOLD_FIXED_TO_BINARY: usize = 53; const FAST_TRACK_THRESHOLD_HEX_TO_BINARY: usize = 64; const FAST_TRACK_THRESHOLD_BINARY_TO_HEX: usize = 64; +/// * 'sign' - `true` indicates that the value is negative; `false` indicates that it is positive. +/// * 'mantissa' - The absolute value represented as an integer without a decimal point. +/// * 'exponent' - The exponent to apply to the mantissa, where the actual value is calculated as `mantissa * 2^exponent`. The exponent can be negative. struct IntermediateRepresentation { sign: bool, mantissa: BigUint, @@ -151,8 +154,8 @@ fn convert( hex_to_binary(line, &mut converted) .expect("Failed to write binary to file"); } else { - intermediate_to_binary( - hex_to_intermediate(line), + to_binary( + from_hex(line), &mut converted, ) .expect("Failed to write binary to file"); @@ -165,8 +168,8 @@ fn convert( float_to_binary(line, &mut converted) .expect("Failed to write binary to file"); } else { - intermediate_to_binary( - float_to_intermediate(line), + to_binary( + from_float(line), &mut converted, ) .expect("Failed to write binary to file"); @@ -179,8 +182,8 @@ fn convert( fixed_to_binary(line, &mut converted, exponent) .expect("Failed to write binary to file"); } else { - intermediate_to_binary( - fixed_to_intermediate(line, exponent), + to_binary( + from_fixed(line, exponent), &mut converted, ) .expect("Failed to write binary to file"); @@ -195,8 +198,8 @@ fn convert( .expect("Failed to write hex to file"); } else { print!("used intermediate"); - intermediate_to_hex( - binary_to_intermediate(line), + to_hex( + from_binary(line), &mut converted, ) .expect("Failed to write binary to file"); @@ -209,8 +212,8 @@ fn convert( binary_to_float(line, &mut converted) .expect("Failed to write float to file"); } else { - intermediate_to_float( - binary_to_intermediate(line), + to_float( + from_binary(line), &mut converted, ) .expect("Failed to write binary to file"); @@ -224,8 +227,8 @@ fn convert( binary_to_fixed(line, &mut converted, exponent) .expect("Failed to write fixed-point to file"); } else { - intermediate_to_fixed( - binary_to_intermediate(line), + to_fixed( + from_binary(line), &mut converted, ) .expect("Failed to write binary to file"); @@ -241,8 +244,8 @@ fn convert( ) .expect("Failed to write fixed-point to file"); } else { - intermediate_to_fixed( - binary_to_intermediate(line), + to_fixed( + from_binary(line), &mut converted, ) .expect("Failed to write binary to file"); @@ -650,7 +653,7 @@ fn binary_to_fixed_bit_slice( /// /// This function will panic if the input string cannot be parsed as a binary number. -fn binary_to_intermediate(binary_string: &str) -> IntermediateRepresentation { +fn from_binary(binary_string: &str) -> IntermediateRepresentation { let bit_width = binary_string.len(); let sign = binary_string.starts_with('0'); @@ -690,7 +693,7 @@ fn binary_to_intermediate(binary_string: &str) -> IntermediateRepresentation { /// This function returns a `std::io::Result<()>` which is `Ok` if the operation /// is successful, or an `Err` if an I/O error occurs while writing to the file. -fn intermediate_to_binary( +fn to_binary( inter_rep: IntermediateRepresentation, filepath_send: &mut Option, ) -> io::Result<()> { @@ -732,7 +735,7 @@ fn intermediate_to_binary( /// # Panics /// /// This function will panic if the input string cannot be parsed as a number. -fn float_to_intermediate(float_string: &str) -> IntermediateRepresentation { +fn from_float(float_string: &str) -> IntermediateRepresentation { let sign = !float_string.starts_with('-'); let float_trimmed = float_string.trim_start_matches('-'); @@ -767,7 +770,7 @@ fn float_to_intermediate(float_string: &str) -> IntermediateRepresentation { /// This function returns a `std::io::Result<()>` which is `Ok` if the operation /// is successful, or an `Err` if an I/O error occurs while writing to the file. -fn intermediate_to_float( +fn to_float( inter_rep: IntermediateRepresentation, filepath_send: &mut Option, ) -> io::Result<()> { @@ -831,7 +834,7 @@ fn intermediate_to_float( /// # Panics /// /// This function will panic if the input string cannot be parsed as a number. -fn fixed_to_intermediate( +fn from_fixed( fixed_string: &str, exp_int: i64, ) -> IntermediateRepresentation { @@ -864,7 +867,7 @@ fn fixed_to_intermediate( /// /// This function returns a `std::io::Result<()>` which is `Ok` if the operation /// is successful, or an `Err` if an I/O error occurs while writing to the file. -fn intermediate_to_fixed( +fn to_fixed( inter_rep: IntermediateRepresentation, filepath_send: &mut Option, ) -> io::Result<()> { @@ -940,7 +943,7 @@ fn intermediate_to_fixed( /// /// This function will panic if the input string cannot be parsed as a hexadecimal number. -fn hex_to_intermediate(hex_string: &str) -> IntermediateRepresentation { +fn from_hex(hex_string: &str) -> IntermediateRepresentation { // Get sign value before converting string let sign = !hex_string.starts_with('-'); @@ -974,7 +977,7 @@ fn hex_to_intermediate(hex_string: &str) -> IntermediateRepresentation { /// This function returns a `std::io::Result<()>` which is `Ok` if the operation /// is successful, or an `Err` if an I/O error occurs while writing to the file. -fn intermediate_to_hex( +fn to_hex( inter_rep: IntermediateRepresentation, filepath_send: &mut Option, ) -> io::Result<()> { @@ -995,4 +998,4 @@ fn intermediate_to_hex( } Ok(()) -} +} \ No newline at end of file From 85f6e21fd69a395edf27d8e8879f070999146f9d Mon Sep 17 00:00:00 2001 From: Angelica Schell Date: Mon, 12 Aug 2024 06:18:32 -0600 Subject: [PATCH 09/15] Corrected binary_to_intermediate by requiring bit width from the command line. --- tools/data-conversion/src/main.rs | 74 ++++++++++++------------------- 1 file changed, 28 insertions(+), 46 deletions(-) diff --git a/tools/data-conversion/src/main.rs b/tools/data-conversion/src/main.rs index 2f244be6f7..6fa3baf2b3 100644 --- a/tools/data-conversion/src/main.rs +++ b/tools/data-conversion/src/main.rs @@ -101,7 +101,10 @@ struct Arguments { /// optional for fixed_to_binary using bit slicing. If choosen, will use bit slicing. #[argh(switch, short = 'b')] bits: bool, - // optional switch for + + /// optional for use with to_binary + #[argh(option, short = 'w')] + width: usize, } fn main() { @@ -114,6 +117,7 @@ fn main() { args.totype, args.exp, args.bits, + args.width, ); } @@ -141,6 +145,7 @@ fn convert( convert_to: NumType, exponent: i64, bits: bool, + width: usize, ) { // Create the output file if filepath_send is Some let mut converted: Option = filepath_send @@ -154,11 +159,8 @@ fn convert( hex_to_binary(line, &mut converted) .expect("Failed to write binary to file"); } else { - to_binary( - from_hex(line), - &mut converted, - ) - .expect("Failed to write binary to file"); + to_binary(from_hex(line), &mut converted) + .expect("Failed to write binary to file"); } } } @@ -168,11 +170,8 @@ fn convert( float_to_binary(line, &mut converted) .expect("Failed to write binary to file"); } else { - to_binary( - from_float(line), - &mut converted, - ) - .expect("Failed to write binary to file"); + to_binary(from_float(line), &mut converted) + .expect("Failed to write binary to file"); } } } @@ -182,11 +181,8 @@ fn convert( fixed_to_binary(line, &mut converted, exponent) .expect("Failed to write binary to file"); } else { - to_binary( - from_fixed(line, exponent), - &mut converted, - ) - .expect("Failed to write binary to file"); + to_binary(from_fixed(line, exponent), &mut converted) + .expect("Failed to write binary to file"); } } } @@ -198,11 +194,8 @@ fn convert( .expect("Failed to write hex to file"); } else { print!("used intermediate"); - to_hex( - from_binary(line), - &mut converted, - ) - .expect("Failed to write binary to file"); + to_hex(from_binary(line, width), &mut converted) + .expect("Failed to write binary to file"); } } } @@ -212,11 +205,8 @@ fn convert( binary_to_float(line, &mut converted) .expect("Failed to write float to file"); } else { - to_float( - from_binary(line), - &mut converted, - ) - .expect("Failed to write binary to file"); + to_float(from_binary(line, width), &mut converted) + .expect("Failed to write binary to file"); } } } @@ -227,11 +217,8 @@ fn convert( binary_to_fixed(line, &mut converted, exponent) .expect("Failed to write fixed-point to file"); } else { - to_fixed( - from_binary(line), - &mut converted, - ) - .expect("Failed to write binary to file"); + to_fixed(from_binary(line, width), &mut converted) + .expect("Failed to write binary to file"); } } } else { @@ -244,11 +231,8 @@ fn convert( ) .expect("Failed to write fixed-point to file"); } else { - to_fixed( - from_binary(line), - &mut converted, - ) - .expect("Failed to write binary to file"); + to_fixed(from_binary(line, width), &mut converted) + .expect("Failed to write binary to file"); } } } @@ -653,9 +637,10 @@ fn binary_to_fixed_bit_slice( /// /// This function will panic if the input string cannot be parsed as a binary number. -fn from_binary(binary_string: &str) -> IntermediateRepresentation { - let bit_width = binary_string.len(); - +fn from_binary( + binary_string: &str, + bit_width: usize, +) -> IntermediateRepresentation { let sign = binary_string.starts_with('0'); let binary_value = BigUint::from_str_radix(binary_string, 2) @@ -834,18 +819,15 @@ fn to_float( /// # Panics /// /// This function will panic if the input string cannot be parsed as a number. -fn from_fixed( - fixed_string: &str, - exp_int: i64, -) -> IntermediateRepresentation { +fn from_fixed(fixed_string: &str, exp_int: i64) -> IntermediateRepresentation { let sign = !fixed_string.starts_with('-'); let fixed_trimmed = fixed_string.trim_start_matches('-'); - let mantissa_string = &format!("{fixed_trimmed}"); + let mantissa_string = fixed_trimmed.to_string(); IntermediateRepresentation { sign, - mantissa: BigUint::from_str(mantissa_string).expect("Invalid number"), + mantissa: BigUint::from_str(&mantissa_string).expect("Invalid number"), exponent: exp_int, } } @@ -998,4 +980,4 @@ fn to_hex( } Ok(()) -} \ No newline at end of file +} From b44ea8cc43690316472648edb5d21b088534ac4e Mon Sep 17 00:00:00 2001 From: Angelica Schell Date: Mon, 12 Aug 2024 07:35:46 -0600 Subject: [PATCH 10/15] Updated from_hex to match the implementation of from_binary --- tools/data-conversion/src/main.rs | 55 ++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/tools/data-conversion/src/main.rs b/tools/data-conversion/src/main.rs index 6fa3baf2b3..ab3397cd2b 100644 --- a/tools/data-conversion/src/main.rs +++ b/tools/data-conversion/src/main.rs @@ -102,7 +102,7 @@ struct Arguments { #[argh(switch, short = 'b')] bits: bool, - /// optional for use with to_binary + /// optional for use with to_binary and from_binary #[argh(option, short = 'w')] width: usize, } @@ -159,7 +159,7 @@ fn convert( hex_to_binary(line, &mut converted) .expect("Failed to write binary to file"); } else { - to_binary(from_hex(line), &mut converted) + to_binary(from_hex(line, width), &mut converted, width) .expect("Failed to write binary to file"); } } @@ -170,7 +170,7 @@ fn convert( float_to_binary(line, &mut converted) .expect("Failed to write binary to file"); } else { - to_binary(from_float(line), &mut converted) + to_binary(from_float(line), &mut converted, width) .expect("Failed to write binary to file"); } } @@ -181,8 +181,12 @@ fn convert( fixed_to_binary(line, &mut converted, exponent) .expect("Failed to write binary to file"); } else { - to_binary(from_fixed(line, exponent), &mut converted) - .expect("Failed to write binary to file"); + to_binary( + from_fixed(line, exponent), + &mut converted, + width, + ) + .expect("Failed to write binary to file"); } } } @@ -627,6 +631,7 @@ fn binary_to_fixed_bit_slice( /// # Arguments /// /// * `binary_string` - A string slice containing the binary number to be converted. +/// * `bit_width` - A number representing the width of each binary number /// /// # Returns /// @@ -672,6 +677,7 @@ fn from_binary( /// * `inter_rep` - The intermediate representation to be converted. /// * `filepath_send` - A mutable reference to an optional `File` where the binary string /// will be written. If `None`, the result is written to stdout. +/// * `bit_width` - A number representing the width of each binary number /// /// # Returns /// @@ -681,6 +687,7 @@ fn from_binary( fn to_binary( inter_rep: IntermediateRepresentation, filepath_send: &mut Option, + bit_width: usize, // Bit width specified by the user ) -> io::Result<()> { let inter_value = if inter_rep.sign { BigInt::from(inter_rep.mantissa) @@ -688,8 +695,20 @@ fn to_binary( -BigInt::from(inter_rep.mantissa) }; - let binary_str = inter_value.to_str_radix(2); + // Convert the value to a binary string + let mut binary_str = inter_value.to_str_radix(2); + + // Handle two's complement for negative numbers + if inter_value < BigInt::from(0) { + let max_value = BigInt::from(1) << bit_width; + let two_complement = max_value + inter_value; + binary_str = two_complement.to_str_radix(2); + } + + // At this point, binary_str should already be at the correct bit width + // No padding or truncation is necessary + // Write to file or stdout if let Some(file) = filepath_send { file.write_all(binary_str.as_bytes())?; file.write_all(b"\n")?; @@ -925,20 +944,26 @@ fn to_fixed( /// /// This function will panic if the input string cannot be parsed as a hexadecimal number. -fn from_hex(hex_string: &str) -> IntermediateRepresentation { - // Get sign value before converting string - let sign = !hex_string.starts_with('-'); - - // Remove the '-' sign if present - let cleaned_hex_string = if sign { hex_string } else { &hex_string[1..] }; - +fn from_hex(hex_string: &str, width: usize) -> IntermediateRepresentation { // Convert the cleaned hexadecimal string to BigUint - let hex_value = BigUint::from_str_radix(cleaned_hex_string, 16) + let hex_value = BigUint::from_str_radix(hex_string, 16) .expect("Invalid hexadecimal string"); + // Determine if the value is negative based on the MSB + let sign_bit = BigUint::from(1u64) << (width - 1); + let sign = &hex_value & &sign_bit == BigUint::from(0u64); + + let mantissa = if sign { + hex_value + } else { + // Calculate the two's complement for negative values + let max_value = BigUint::from(1u64) << width; + &max_value - &hex_value + }; + IntermediateRepresentation { sign, - mantissa: hex_value, + mantissa, exponent: 0, } } From cb240e2ac6a32ed4d5023f95bc6f08b66a4ad9dc Mon Sep 17 00:00:00 2001 From: Angelica Schell Date: Wed, 14 Aug 2024 06:16:10 -0600 Subject: [PATCH 11/15] corrected bit width command line input so that it is optional" --- tools/data-conversion/src/main.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tools/data-conversion/src/main.rs b/tools/data-conversion/src/main.rs index ab3397cd2b..fbd7952e73 100644 --- a/tools/data-conversion/src/main.rs +++ b/tools/data-conversion/src/main.rs @@ -103,7 +103,7 @@ struct Arguments { bits: bool, /// optional for use with to_binary and from_binary - #[argh(option, short = 'w')] + #[argh(option, default = "0")] width: usize, } @@ -448,10 +448,7 @@ fn binary_to_float( let binary_value = u64::from_str_radix(binary_string, 2) .expect("Failed to parse binary string"); - // Interpret the integer as the binary representation of a floating-point number - let float_value = f64::from_bits(binary_value); - - let formated_float_str = format!("{:?}", float_value); + let formated_float_str = format!("{:?}", binary_value); if let Some(file) = filepath_send.as_mut() { // Write binary string to the file From de786e529b32e6214592af6fec27dfca37e20000 Mon Sep 17 00:00:00 2001 From: Angelica Schell Date: Wed, 18 Sep 2024 09:02:41 -0400 Subject: [PATCH 12/15] Seperation of NumType and FileType --- tools/data-conversion/src/main.rs | 249 +++++++++++++++++------------- 1 file changed, 142 insertions(+), 107 deletions(-) diff --git a/tools/data-conversion/src/main.rs b/tools/data-conversion/src/main.rs index fbd7952e73..3811f3f74e 100644 --- a/tools/data-conversion/src/main.rs +++ b/tools/data-conversion/src/main.rs @@ -36,45 +36,83 @@ struct ParseNumTypeError; impl fmt::Display for ParseNumTypeError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "invalid number type") + write!(f, "invalid numeric type") } } impl Error for ParseNumTypeError {} -#[derive(Debug, PartialEq, Clone, Copy)] // Add PartialEq derivation here +#[derive(Debug, PartialEq, Clone, Copy)] enum NumType { - Binary, Float, - Hex, Fixed, } +impl FromStr for NumType { + type Err = ParseNumTypeError; + + fn from_str(input: &str) -> Result { + match input { + "float" => Ok(NumType::Float), + "fixed" => Ok(NumType::Fixed), + _ => Err(ParseNumTypeError), + } + } +} + impl ToString for NumType { fn to_string(&self) -> String { match self { - NumType::Binary => "binary".to_string(), NumType::Float => "float".to_string(), - NumType::Hex => "hex".to_string(), NumType::Fixed => "fixed".to_string(), } } } -impl FromStr for NumType { + +#[derive(Debug)] +struct ParseFileTypeError; + +impl fmt::Display for ParseFileTypeError { + fn fmt(&self, f: &mut fmt:: Formatter<'_>) -> fmt::Result { + write!(f, "invalid file type") + } +} + +impl Error for ParseFileTypeError {} + +#[derive(Debug, PartialEq, Clone, Copy)] +enum FileType { + Binary, + Hex, + Decimal, +} + +impl std::str::FromStr for FileType { type Err = ParseNumTypeError; - fn from_str(input: &str) -> Result { - match input { - "binary" => Ok(NumType::Binary), - "float" => Ok(NumType::Float), - "hex" => Ok(NumType::Hex), - "fixed" => Ok(NumType::Fixed), + fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + "binary" => Ok(FileType::Binary), + "hex" => Ok(FileType::Hex), + "decfloat" => Ok(FileType::Decimal), _ => Err(ParseNumTypeError), } } } +impl ToString for FileType { + fn to_string(&self) -> String { + match self { + FileType::Hex => "hex".to_string(), + FileType::Binary => "binary".to_string(), + FileType::Decimal => "decimal".to_string(), + } + } +} + + + #[derive(FromArgs)] /// get arguments to convert struct Arguments { @@ -86,13 +124,21 @@ struct Arguments { #[argh(option)] to: Option, - /// type to convert from + /// num type to convert from #[argh(option)] - ftype: NumType, + fromnum: NumType, - /// type to convert to + /// file type to convert from #[argh(option)] - totype: NumType, + fromfile: FileType, + + /// num type to convert to + #[argh(option)] + tonum: NumType, + + /// file type to convert to + #[argh(option)] + tofile: FileType, /// optional exponent for fixed_to_binary -> default is -1 #[argh(option, default = "-1")] @@ -105,6 +151,10 @@ struct Arguments { /// optional for use with to_binary and from_binary #[argh(option, default = "0")] width: usize, + + /// optional flag to force the inter-rep path + #[argh(switch, short = 'i')] + inter: bool } fn main() { @@ -113,11 +163,14 @@ fn main() { convert( &args.from, &args.to, - args.ftype, - args.totype, + args.fromnum, + args.fromfile, + args.tonum, + args.tofile, args.exp, args.bits, args.width, + args.inter, ); } @@ -141,124 +194,104 @@ fn main() { fn convert( filepath_get: &String, filepath_send: &Option, - convert_from: NumType, - convert_to: NumType, + fromnum: NumType, + fromfile: FileType, + tonum: NumType, + tofile: FileType, exponent: i64, bits: bool, width: usize, + inter: bool, ) { // Create the output file if filepath_send is Some let mut converted: Option = filepath_send .as_ref() .map(|path| File::create(path).expect("creation failed")); - match (convert_from, convert_to) { - (NumType::Hex, NumType::Binary) => { - for line in read_to_string(filepath_get).unwrap().lines() { - if line.len() <= FAST_TRACK_THRESHOLD_HEX_TO_BINARY { - hex_to_binary(line, &mut converted) - .expect("Failed to write binary to file"); - } else { - to_binary(from_hex(line, width), &mut converted, width) - .expect("Failed to write binary to file"); - } - } - } - (NumType::Float, NumType::Binary) => { - for line in read_to_string(filepath_get).unwrap().lines() { - if line.len() <= FAST_TRACK_THRESHOLD_FLOAT_TO_BINARY { - float_to_binary(line, &mut converted) - .expect("Failed to write binary to file"); - } else { - to_binary(from_float(line), &mut converted, width) - .expect("Failed to write binary to file"); + match (fromnum, tonum) { + (NumType:: Float, NumType::Float) => { + match(fromfile, tofile){ + (FileType:: Hex, FileType::Binary) => { + for line in read_to_string(filepath_get).unwrap().lines() { + if line.len() <= FAST_TRACK_THRESHOLD_HEX_TO_BINARY && !inter{ + hex_to_binary(line, &mut converted) + .expect("Failed to write binary to file"); + } else { + to_binary(from_hex(line, width), &mut converted, width) + .expect("Failed to write binary to file"); + } + } } - } - } - (NumType::Fixed, NumType::Binary) => { - for line in read_to_string(filepath_get).unwrap().lines() { - if line.len() <= FAST_TRACK_THRESHOLD_FIXED_TO_BINARY { - fixed_to_binary(line, &mut converted, exponent) - .expect("Failed to write binary to file"); - } else { - to_binary( - from_fixed(line, exponent), - &mut converted, - width, - ) - .expect("Failed to write binary to file"); + (FileType:: Decimal, FileType::Binary)=>{ + for line in read_to_string(filepath_get).unwrap().lines() { + if line.len() <= FAST_TRACK_THRESHOLD_FLOAT_TO_BINARY && !inter { + float_to_binary(line, &mut converted) + .expect("Failed to write binary to file"); + } else { + to_binary(from_float(line), &mut converted, width) + .expect("Failed to write binary to file"); + } + } } - } - } - (NumType::Binary, NumType::Hex) => { - for line in read_to_string(filepath_get).unwrap().lines() { - print!("used fastpath"); - if line.len() <= FAST_TRACK_THRESHOLD_BINARY_TO_HEX { - binary_to_hex(line, &mut converted) - .expect("Failed to write hex to file"); - } else { - print!("used intermediate"); - to_hex(from_binary(line, width), &mut converted) - .expect("Failed to write binary to file"); + (FileType:: Binary, FileType::Hex)=>{ + for line in read_to_string(filepath_get).unwrap().lines() { + print!("used fastpath"); + if line.len() <= FAST_TRACK_THRESHOLD_BINARY_TO_HEX && !inter { + binary_to_hex(line, &mut converted) + .expect("Failed to write hex to file"); + } else { + print!("used intermediate"); + to_hex(from_binary(line, width), &mut converted) + .expect("Failed to write binary to file"); + } + } } - } - } - (NumType::Binary, NumType::Float) => { - for line in read_to_string(filepath_get).unwrap().lines() { - if line.len() <= FAST_TRACK_THRESHOLD_BINARY_TO_FLOAT { - binary_to_float(line, &mut converted) - .expect("Failed to write float to file"); - } else { - to_float(from_binary(line, width), &mut converted) - .expect("Failed to write binary to file"); + (FileType:: Binary, FileType::Decimal)=>{ + for line in read_to_string(filepath_get).unwrap().lines() { + if line.len() <= FAST_TRACK_THRESHOLD_BINARY_TO_FLOAT && !inter { + binary_to_float(line, &mut converted) + .expect("Failed to write float to file"); + } else { + to_float(from_binary(line, width), &mut converted) + .expect("Failed to write binary to file"); + } + } } - } - } - (NumType::Binary, NumType::Fixed) => { - if !bits { - for line in read_to_string(filepath_get).unwrap().lines() { - if line.len() <= FAST_TRACK_THRESHOLD_BINARY_TO_FIXED { - binary_to_fixed(line, &mut converted, exponent) - .expect("Failed to write fixed-point to file"); - } else { - to_fixed(from_binary(line, width), &mut converted) - .expect("Failed to write binary to file"); + (FileType:: Hex, FileType::Decimal)=>{ + for line in read_to_string(filepath_get).unwrap().lines() { + to_float(from_hex(line, width), &mut converted) + .expect("Failed to write binary to file"); } } - } else { - for line in read_to_string(filepath_get).unwrap().lines() { - if line.len() <= FAST_TRACK_THRESHOLD_BINARY_TO_FIXED { - binary_to_fixed_bit_slice( - line, - &mut converted, - exponent, - ) - .expect("Failed to write fixed-point to file"); - } else { - to_fixed(from_binary(line, width), &mut converted) - .expect("Failed to write binary to file"); + (FileType:: Decimal, FileType::Hex)=>{ + for line in read_to_string(filepath_get).unwrap().lines() { + to_hex(from_float(line), &mut converted) + .expect("Failed to write binary to file"); } } + (_, _)=>{ + panic!("Invalid Conversion of File Types") + } } } _ => panic!( "Conversion from {} to {} is not supported", - convert_from.to_string(), - convert_to.to_string() + fromnum.to_string(), + tonum.to_string() ), } if let Some(filepath) = filepath_send { eprintln!( "Successfully converted from {} to {} in {}", - convert_from.to_string(), - convert_to.to_string(), + fromnum.to_string(), + tonum.to_string(), filepath ); } else { eprintln!( "Successfully converted from {} to {}", - convert_from.to_string(), - convert_to.to_string(), + fromnum.to_string(), + tonum.to_string(), ); } } @@ -350,6 +383,8 @@ fn float_to_binary( /// # Error /// /// This function will panic if the input string cannot be parsed as a hexadecimal number. +/// +/// This does not differentiate between floating and fixed. It just treats any hex as an integer. fn hex_to_binary( hex_string: &str, filepath_send: &mut Option, @@ -941,7 +976,7 @@ fn to_fixed( /// /// This function will panic if the input string cannot be parsed as a hexadecimal number. -fn from_hex(hex_string: &str, width: usize) -> IntermediateRepresentation { +fn from_hex(hex_string: &str, width: usize, float_or_fixed: NumType) -> IntermediateRepresentation { // Convert the cleaned hexadecimal string to BigUint let hex_value = BigUint::from_str_radix(hex_string, 16) .expect("Invalid hexadecimal string"); From 1c154e1aef07425e7642d7595596ee6d067df8a2 Mon Sep 17 00:00:00 2001 From: Angelica Schell Date: Thu, 19 Sep 2024 11:24:17 -0400 Subject: [PATCH 13/15] Added U8 Vector Representation --- tools/data-conversion/src/ir.rs | 58 +++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 tools/data-conversion/src/ir.rs diff --git a/tools/data-conversion/src/ir.rs b/tools/data-conversion/src/ir.rs new file mode 100644 index 0000000000..1e4db8d456 --- /dev/null +++ b/tools/data-conversion/src/ir.rs @@ -0,0 +1,58 @@ +pub fn binary_to_u8_vec(binary: &str) -> Result, String> { + let mut padded_binary: String = binary.to_string(); + + // If the binary string length is not a multiple of 8, pad it with leading zeros + let padding = 8 - (padded_binary.len() % 8); + if padding != 8 { + padded_binary = "0".repeat(padding) + &padded_binary; + } + + let mut vec = Vec::new(); + + for i in (0..padded_binary.len()).step_by(8) { + let byte_str = &padded_binary[i..i + 8]; + match u8::from_str_radix(byte_str, 2) { + Ok(byte) => vec.push(byte), + Err(_) => return Err(String::from("Invalid binary string")), + } + } + + Ok(vec) +} + +pub fn hex_to_u8_vec(hex: &str) -> Result, String> { + let mut padded_hex = hex.to_string(); + + let padding = 2 - (padded_hex.len() % 2); + if padding != 2 { + padded_hex = "0".repeat(padding) + &padded_hex; + } + + let mut vec = Vec::new(); + + for i in (0..padded_hex.len()).step_by(2) { + let byte_str = &padded_hex[i..i + 8]; + match u8::from_str_radix(byte_str, 2){ + Ok(byte) => vec.push(byte), + Err(_) => return Err(String::from("Invalid binary string")), + } + } + Ok(vec) +} + + +pub fn decimal_to_u8_vec(decimal: &str) -> Result, String> { + let mut vec = Vec::new(); + + // Iterate over each character in the decimal string + for c in decimal.chars() { + // Check if the character is a digit + if let Some(digit) = c.to_digit(10) { + // Convert the digit (u32) to a u8 and push it to the vector + vec.push(digit as u8); + } else { + return Err(format!("Invalid character '{}' in decimal string", c)); + } + } + Ok(vec) +} \ No newline at end of file From 21df9c21bbe18ad9a23ab836baf728657a712832 Mon Sep 17 00:00:00 2001 From: Angelica Schell Date: Thu, 19 Sep 2024 15:32:06 -0400 Subject: [PATCH 14/15] Started modularizing --- tools/data-conversion/src/ir.rs | 421 +++++++++++++++++++++++--- tools/data-conversion/src/main.rs | 404 +----------------------- tools/data-conversion/src/results.txt | 7 + tools/data-conversion/src/u8vector.rs | 58 ++++ 4 files changed, 454 insertions(+), 436 deletions(-) create mode 100644 tools/data-conversion/src/results.txt create mode 100644 tools/data-conversion/src/u8vector.rs diff --git a/tools/data-conversion/src/ir.rs b/tools/data-conversion/src/ir.rs index 1e4db8d456..f800c848dd 100644 --- a/tools/data-conversion/src/ir.rs +++ b/tools/data-conversion/src/ir.rs @@ -1,58 +1,399 @@ -pub fn binary_to_u8_vec(binary: &str) -> Result, String> { - let mut padded_binary: String = binary.to_string(); +use num_bigint::BigInt; +use num_bigint::BigUint; +use num_traits::Num; +use std::fs::File; +use std::io::{self, Write}; +use std::str::FromStr; - // If the binary string length is not a multiple of 8, pad it with leading zeros - let padding = 8 - (padded_binary.len() % 8); - if padding != 8 { - padded_binary = "0".repeat(padding) + &padded_binary; + +pub struct IntermediateRepresentation { + sign: bool, + mantissa: BigUint, + exponent: i64, +} + + +/// Converts a string representation of a binary number the intermediate representation. +/// +/// This function takes a string slice representing a binary number, +/// converts it to a `BigUint`, determines the sign, and constructs an +/// `IntermediateRepresentation` containing the sign, mantissa, and exponent. +/// +/// # Arguments +/// +/// * `binary_string` - A string slice containing the binary number to be converted. +/// * `bit_width` - A number representing the width of each binary number +/// +/// # Returns +/// +/// This function returns an `IntermediateRepresentation` containing the sign, mantissa, +/// and exponent of the binary number. +/// +/// # Panics +/// +/// This function will panic if the input string cannot be parsed as a binary number. + +pub fn from_binary( + binary_string: &str, + bit_width: usize, +) -> IntermediateRepresentation { + let sign = binary_string.starts_with('0'); + + let binary_value = BigUint::from_str_radix(binary_string, 2) + .expect("Invalid binary string"); + + let mantissa = if sign { + binary_value + } else { + // Calculate the two's complement for negative values + let max_value = BigUint::from(1u64) << bit_width; + &max_value - &binary_value + }; + + IntermediateRepresentation { + sign, + mantissa, + exponent: 0, } +} + +/// Converts the intermediate representation to a binary string and writes it to a file or stdout. +/// +/// This function takes an `IntermediateRepresentation`, converts the mantissa to a `BigInt` +/// applying the sign, converts the resulting `BigInt` to a binary string, and writes +/// the binary string to the specified file or stdout. +/// +/// # Arguments +/// +/// * `inter_rep` - The intermediate representation to be converted. +/// * `filepath_send` - A mutable reference to an optional `File` where the binary string +/// will be written. If `None`, the result is written to stdout. +/// * `bit_width` - A number representing the width of each binary number +/// +/// # Returns +/// +/// This function returns a `std::io::Result<()>` which is `Ok` if the operation +/// is successful, or an `Err` if an I/O error occurs while writing to the file. - let mut vec = Vec::new(); +pub fn to_binary( + inter_rep: IntermediateRepresentation, + filepath_send: &mut Option, + bit_width: usize, // Bit width specified by the user +) -> io::Result<()> { + let inter_value = if inter_rep.sign { + BigInt::from(inter_rep.mantissa) + } else { + -BigInt::from(inter_rep.mantissa) + }; - for i in (0..padded_binary.len()).step_by(8) { - let byte_str = &padded_binary[i..i + 8]; - match u8::from_str_radix(byte_str, 2) { - Ok(byte) => vec.push(byte), - Err(_) => return Err(String::from("Invalid binary string")), - } + // Convert the value to a binary string + let mut binary_str = inter_value.to_str_radix(2); + + // Handle two's complement for negative numbers + if inter_value < BigInt::from(0) { + let max_value = BigInt::from(1) << bit_width; + let two_complement = max_value + inter_value; + binary_str = two_complement.to_str_radix(2); } - Ok(vec) + // At this point, binary_str should already be at the correct bit width + // No padding or truncation is necessary + + // Write to file or stdout + if let Some(file) = filepath_send { + file.write_all(binary_str.as_bytes())?; + file.write_all(b"\n")?; + } else { + std::io::stdout().write_all(binary_str.as_bytes())?; + std::io::stdout().write_all(b"\n")?; + } + + Ok(()) +} + +/// Converts a string representation of a floating-point number to the intermediate representation. +/// +/// This function takes a string slice representing a floating-point number, +/// splits it into integer and fractional parts, constructs the mantissa, +/// sets the exponent based on the length of the fractional part, and +/// constructs an `IntermediateRepresentation` containing the sign, mantissa, and exponent. +/// +/// # Arguments +/// +/// * `float_string` - A string slice containing the floating-point number to be converted. +/// +/// # Returns +/// +/// This function returns an `IntermediateRepresentation` containing the sign, mantissa, +/// and exponent of the floating-point number. +/// +/// # Panics +/// +/// This function will panic if the input string cannot be parsed as a number. +pub fn from_float(float_string: &str) -> IntermediateRepresentation { + let sign = !float_string.starts_with('-'); + let float_trimmed = float_string.trim_start_matches('-'); + + let parts: Vec<&str> = float_trimmed.split('.').collect(); + let integer_part = parts[0]; + let fractional_part = if parts.len() > 1 { parts[1] } else { "0" }; + // Prob not the best way to do this + let mantissa_string = format!("{integer_part}{fractional_part}"); + + IntermediateRepresentation { + sign, + mantissa: BigUint::from_str(&mantissa_string).expect("Invalid number"), + exponent: -(fractional_part.len() as i64), + } } -pub fn hex_to_u8_vec(hex: &str) -> Result, String> { - let mut padded_hex = hex.to_string(); +/// Converts the intermediate representation to a floating-point number string and writes it to a file or stdout. +/// +/// This function takes an `IntermediateRepresentation`, converts the mantissa to a string, +/// inserts the decimal point at the correct position based on the exponent, constructs +/// the floating-point number string applying the sign, and writes the resulting string +/// to the specified file or stdout. +/// +/// # Arguments +/// +/// * `inter_rep` - The intermediate representation to be converted. +/// * `filepath_send` - A mutable reference to an optional `File` where the floating-point +/// number string will be written. If `None`, the result is written to stdout. +/// +/// # Returns +/// +/// This function returns a `std::io::Result<()>` which is `Ok` if the operation +/// is successful, or an `Err` if an I/O error occurs while writing to the file. - let padding = 2 - (padded_hex.len() % 2); - if padding != 2 { - padded_hex = "0".repeat(padding) + &padded_hex; +pub fn to_float( + inter_rep: IntermediateRepresentation, + filepath_send: &mut Option, +) -> io::Result<()> { + let mut mantissa_str = inter_rep.mantissa.to_string(); + + // Determine the position to insert the decimal point + let mut decimal_pos = mantissa_str.len() as i64 - inter_rep.exponent; + + // Handle cases where the decimal position is before the first digit + if decimal_pos <= 0 { + let zero_padding = "0".repeat(-decimal_pos as usize); + mantissa_str = format!("{}{}", zero_padding, mantissa_str); + decimal_pos = 1; // Decimal point will be at the first digit position } - let mut vec = Vec::new(); + // Convert to &str for split_at + let mantissa_str = mantissa_str.as_str(); + + // Insert the decimal point + let decimal_position = decimal_pos as usize; + let (integer_part, fractional_part) = if decimal_position > 0 { + mantissa_str.split_at(decimal_position) + } else { + ("0", mantissa_str) + }; - for i in (0..padded_hex.len()).step_by(2) { - let byte_str = &padded_hex[i..i + 8]; - match u8::from_str_radix(byte_str, 2){ - Ok(byte) => vec.push(byte), - Err(_) => return Err(String::from("Invalid binary string")), - } + let result = if inter_rep.sign { + format!("{}.{}", integer_part, fractional_part) + } else { + format!("-{}.{}", integer_part, fractional_part) + }; + + if let Some(file) = filepath_send.as_mut() { + // Write string to the file + file.write_all(result.as_bytes())?; + file.write_all(b"\n")?; + } else { + io::stdout().write_all(result.as_bytes())?; + io::stdout().write_all(b"\n")?; } - Ok(vec) + + Ok(()) } +/// Converts a string representation of a fixed-point number to the intermediate representation. +/// +/// This function takes a string slice representing a fixed-point number and an exponent value, +/// determines the sign, constructs the mantissa, sets the exponent to the given value, and +/// constructs an `IntermediateRepresentation` containing the sign, mantissa, and exponent. +/// +/// # Arguments +/// +/// * `fixed_string` - A string slice containing the fixed-point number to be converted. +/// * `exp_int` - The exponent value for the fixed-point number. +/// +/// # Returns +/// +/// This function returns an `IntermediateRepresentation` containing the sign, mantissa, +/// and exponent of the fixed-point number. +/// +/// # Panics +/// +/// This function will panic if the input string cannot be parsed as a number. +pub fn from_fixed(fixed_string: &str, exp_int: i64) -> IntermediateRepresentation { + let sign = !fixed_string.starts_with('-'); + let fixed_trimmed = fixed_string.trim_start_matches('-'); -pub fn decimal_to_u8_vec(decimal: &str) -> Result, String> { - let mut vec = Vec::new(); + let mantissa_string = fixed_trimmed.to_string(); - // Iterate over each character in the decimal string - for c in decimal.chars() { - // Check if the character is a digit - if let Some(digit) = c.to_digit(10) { - // Convert the digit (u32) to a u8 and push it to the vector - vec.push(digit as u8); - } else { - return Err(format!("Invalid character '{}' in decimal string", c)); - } + IntermediateRepresentation { + sign, + mantissa: BigUint::from_str(&mantissa_string).expect("Invalid number"), + exponent: exp_int, } - Ok(vec) -} \ No newline at end of file +} + +/// Converts the intermediate representation to a fixed-point number string and writes it to a file or stdout. +/// +/// This function takes an `IntermediateRepresentation`, computes the scale factor based on +/// the negative exponent, converts the mantissa to a `BigInt` and multiplies by the scale factor, +/// constructs the fixed-point number string applying the sign, and writes the resulting string +/// to the specified file or stdout. +/// +/// # Arguments +/// +/// * `inter_rep` - The intermediate representation to be converted. +/// * `filepath_send` - A mutable reference to an optional `File` where the fixed-point +/// number string will be written. If `None`, the result is written to stdout. +/// +/// # Returns +/// +/// This function returns a `std::io::Result<()>` which is `Ok` if the operation +/// is successful, or an `Err` if an I/O error occurs while writing to the file. +pub fn to_fixed( + inter_rep: IntermediateRepresentation, + filepath_send: &mut Option, +) -> io::Result<()> { + // Negate exp + let neg_exponent = -inter_rep.exponent; + + // 10^-exp + let scale_factor = BigInt::from(10).pow(neg_exponent as u32); + + // Convert mantissa to BigInt + let mantissa_bigint = BigInt::from(inter_rep.mantissa); + + let mantissa_mult = mantissa_bigint * scale_factor; + + // Apply the sign + let signed_value = if inter_rep.sign { + mantissa_mult + } else { + -mantissa_mult + }; + + // Handle placement of decimal point + let mantissa_str = signed_value.to_string(); + let mantissa_len = mantissa_str.len(); + let adjusted_exponent = inter_rep.exponent + mantissa_len as i64; + + let string = if adjusted_exponent <= 0 { + // Handle case where the exponent indicates a number less than 1 + let zero_padding = "0".repeat(-adjusted_exponent as usize); + format!("0.{}{}", zero_padding, mantissa_str) + } else if adjusted_exponent as usize >= mantissa_len { + // Handle case where the exponent is larger than the length of the mantissa + format!( + "{}{}", + mantissa_str, + "0".repeat(adjusted_exponent as usize - mantissa_len) + ) + } else { + // Normal case + let integer_part = &mantissa_str[..adjusted_exponent as usize]; + let fractional_part = &mantissa_str[adjusted_exponent as usize..]; + format!("{}.{}", integer_part, fractional_part) + }; + + // Write the result to the file or stdout + if let Some(file) = filepath_send.as_mut() { + file.write_all(string.as_bytes())?; + file.write_all(b"\n")?; + } else { + io::stdout().write_all(string.as_bytes())?; + io::stdout().write_all(b"\n")?; + } + + Ok(()) +} + +/// Converts a string representation of a hexadecimal number to the intermediate representation. +/// +/// This function takes a string slice representing a hexadecimal number, +/// converts it to a `BigUint`, determines the sign, and constructs an +/// `IntermediateRepresentation` containing the sign, mantissa, and exponent. +/// +/// # Arguments +/// +/// * `hex_string` - A string slice containing the hexadecimal number to be converted. +/// +/// # Returns +/// +/// This function returns an `IntermediateRepresentation` containing the sign, mantissa, +/// and exponent of the hexadecimal number. +/// +/// # Panics +/// +/// This function will panic if the input string cannot be parsed as a hexadecimal number. + +pub fn from_hex(hex_string: &str, width: usize) -> IntermediateRepresentation { + // Convert the cleaned hexadecimal string to BigUint + let hex_value = BigUint::from_str_radix(hex_string, 16) + .expect("Invalid hexadecimal string"); + + // Determine if the value is negative based on the MSB + let sign_bit = BigUint::from(1u64) << (width - 1); + let sign = &hex_value & &sign_bit == BigUint::from(0u64); + + let mantissa = if sign { + hex_value + } else { + // Calculate the two's complement for negative values + let max_value = BigUint::from(1u64) << width; + &max_value - &hex_value + }; + + IntermediateRepresentation { + sign, + mantissa, + exponent: 0, + } +} + +/// Converts the intermediate representation to a hexadecimal string and writes it to a file or stdout. +/// +/// This function takes an `IntermediateRepresentation`, converts the mantissa to a hexadecimal string, +/// applies the sign, and writes the resulting string to the specified file or stdout. +/// +/// # Arguments +/// +/// * `inter_rep` - The intermediate representation to be converted. +/// * `filepath_send` - A mutable reference to an optional `File` where the hexadecimal string +/// will be written. If `None`, the result is written to stdout. +/// +/// # Returns +/// +/// This function returns a `std::io::Result<()>` which is `Ok` if the operation +/// is successful, or an `Err` if an I/O error occurs while writing to the file. + +pub fn to_hex( + inter_rep: IntermediateRepresentation, + filepath_send: &mut Option, +) -> io::Result<()> { + // Apply the sign + let hex_value = if inter_rep.sign { + inter_rep.mantissa.to_str_radix(16) + } else { + format!("-{}", inter_rep.mantissa.to_str_radix(16)) + }; + + // Write the result to the file or stdout + if let Some(file) = filepath_send.as_mut() { + file.write_all(hex_value.as_bytes())?; + file.write_all(b"\n")?; + } else { + io::stdout().write_all(hex_value.as_bytes())?; + io::stdout().write_all(b"\n")?; + } + + Ok(()) +} diff --git a/tools/data-conversion/src/main.rs b/tools/data-conversion/src/main.rs index 3811f3f74e..f8afa5cee6 100644 --- a/tools/data-conversion/src/main.rs +++ b/tools/data-conversion/src/main.rs @@ -1,10 +1,5 @@ -//use std::env; use argh::FromArgs; -// use core::num; -use num_bigint::BigInt; use num_bigint::BigUint; -// use num_traits::sign; -use num_traits::Num; use std::error::Error; use std::fmt; use std::fs::read_to_string; @@ -12,6 +7,8 @@ use std::fs::File; use std::io::stdout; use std::io::{self, Write}; use std::str::FromStr; +mod u8vector; +mod ir; //cargo run -- --from $PATH1 --to $PATH2 --ftype "from" --totype "to" // Thresholds for using fast-track functions @@ -217,7 +214,7 @@ fn convert( hex_to_binary(line, &mut converted) .expect("Failed to write binary to file"); } else { - to_binary(from_hex(line, width), &mut converted, width) + ir::to_binary(ir::from_hex(line, width), &mut converted, width) .expect("Failed to write binary to file"); } } @@ -228,7 +225,7 @@ fn convert( float_to_binary(line, &mut converted) .expect("Failed to write binary to file"); } else { - to_binary(from_float(line), &mut converted, width) + ir::to_binary(ir::from_float(line), &mut converted, width) .expect("Failed to write binary to file"); } } @@ -241,7 +238,7 @@ fn convert( .expect("Failed to write hex to file"); } else { print!("used intermediate"); - to_hex(from_binary(line, width), &mut converted) + ir::to_hex(ir::from_binary(line, width), &mut converted) .expect("Failed to write binary to file"); } } @@ -252,20 +249,20 @@ fn convert( binary_to_float(line, &mut converted) .expect("Failed to write float to file"); } else { - to_float(from_binary(line, width), &mut converted) + ir::to_float(ir::from_binary(line, width), &mut converted) .expect("Failed to write binary to file"); } } } (FileType:: Hex, FileType::Decimal)=>{ for line in read_to_string(filepath_get).unwrap().lines() { - to_float(from_hex(line, width), &mut converted) + ir::to_float(ir::from_hex(line, width), &mut converted) .expect("Failed to write binary to file"); } } (FileType:: Decimal, FileType::Hex)=>{ for line in read_to_string(filepath_get).unwrap().lines() { - to_hex(from_float(line), &mut converted) + ir::to_hex(ir::from_float(line), &mut converted) .expect("Failed to write binary to file"); } } @@ -653,388 +650,3 @@ fn binary_to_fixed_bit_slice( Ok(()) } - -/// Converts a string representation of a binary number the intermediate representation. -/// -/// This function takes a string slice representing a binary number, -/// converts it to a `BigUint`, determines the sign, and constructs an -/// `IntermediateRepresentation` containing the sign, mantissa, and exponent. -/// -/// # Arguments -/// -/// * `binary_string` - A string slice containing the binary number to be converted. -/// * `bit_width` - A number representing the width of each binary number -/// -/// # Returns -/// -/// This function returns an `IntermediateRepresentation` containing the sign, mantissa, -/// and exponent of the binary number. -/// -/// # Panics -/// -/// This function will panic if the input string cannot be parsed as a binary number. - -fn from_binary( - binary_string: &str, - bit_width: usize, -) -> IntermediateRepresentation { - let sign = binary_string.starts_with('0'); - - let binary_value = BigUint::from_str_radix(binary_string, 2) - .expect("Invalid binary string"); - - let mantissa = if sign { - binary_value - } else { - // Calculate the two's complement for negative values - let max_value = BigUint::from(1u64) << bit_width; - &max_value - &binary_value - }; - - IntermediateRepresentation { - sign, - mantissa, - exponent: 0, - } -} - -/// Converts the intermediate representation to a binary string and writes it to a file or stdout. -/// -/// This function takes an `IntermediateRepresentation`, converts the mantissa to a `BigInt` -/// applying the sign, converts the resulting `BigInt` to a binary string, and writes -/// the binary string to the specified file or stdout. -/// -/// # Arguments -/// -/// * `inter_rep` - The intermediate representation to be converted. -/// * `filepath_send` - A mutable reference to an optional `File` where the binary string -/// will be written. If `None`, the result is written to stdout. -/// * `bit_width` - A number representing the width of each binary number -/// -/// # Returns -/// -/// This function returns a `std::io::Result<()>` which is `Ok` if the operation -/// is successful, or an `Err` if an I/O error occurs while writing to the file. - -fn to_binary( - inter_rep: IntermediateRepresentation, - filepath_send: &mut Option, - bit_width: usize, // Bit width specified by the user -) -> io::Result<()> { - let inter_value = if inter_rep.sign { - BigInt::from(inter_rep.mantissa) - } else { - -BigInt::from(inter_rep.mantissa) - }; - - // Convert the value to a binary string - let mut binary_str = inter_value.to_str_radix(2); - - // Handle two's complement for negative numbers - if inter_value < BigInt::from(0) { - let max_value = BigInt::from(1) << bit_width; - let two_complement = max_value + inter_value; - binary_str = two_complement.to_str_radix(2); - } - - // At this point, binary_str should already be at the correct bit width - // No padding or truncation is necessary - - // Write to file or stdout - if let Some(file) = filepath_send { - file.write_all(binary_str.as_bytes())?; - file.write_all(b"\n")?; - } else { - std::io::stdout().write_all(binary_str.as_bytes())?; - std::io::stdout().write_all(b"\n")?; - } - - Ok(()) -} - -/// Converts a string representation of a floating-point number to the intermediate representation. -/// -/// This function takes a string slice representing a floating-point number, -/// splits it into integer and fractional parts, constructs the mantissa, -/// sets the exponent based on the length of the fractional part, and -/// constructs an `IntermediateRepresentation` containing the sign, mantissa, and exponent. -/// -/// # Arguments -/// -/// * `float_string` - A string slice containing the floating-point number to be converted. -/// -/// # Returns -/// -/// This function returns an `IntermediateRepresentation` containing the sign, mantissa, -/// and exponent of the floating-point number. -/// -/// # Panics -/// -/// This function will panic if the input string cannot be parsed as a number. -fn from_float(float_string: &str) -> IntermediateRepresentation { - let sign = !float_string.starts_with('-'); - let float_trimmed = float_string.trim_start_matches('-'); - - let parts: Vec<&str> = float_trimmed.split('.').collect(); - let integer_part = parts[0]; - let fractional_part = if parts.len() > 1 { parts[1] } else { "0" }; - // Prob not the best way to do this - let mantissa_string = format!("{integer_part}{fractional_part}"); - - IntermediateRepresentation { - sign, - mantissa: BigUint::from_str(&mantissa_string).expect("Invalid number"), - exponent: -(fractional_part.len() as i64), - } -} - -/// Converts the intermediate representation to a floating-point number string and writes it to a file or stdout. -/// -/// This function takes an `IntermediateRepresentation`, converts the mantissa to a string, -/// inserts the decimal point at the correct position based on the exponent, constructs -/// the floating-point number string applying the sign, and writes the resulting string -/// to the specified file or stdout. -/// -/// # Arguments -/// -/// * `inter_rep` - The intermediate representation to be converted. -/// * `filepath_send` - A mutable reference to an optional `File` where the floating-point -/// number string will be written. If `None`, the result is written to stdout. -/// -/// # Returns -/// -/// This function returns a `std::io::Result<()>` which is `Ok` if the operation -/// is successful, or an `Err` if an I/O error occurs while writing to the file. - -fn to_float( - inter_rep: IntermediateRepresentation, - filepath_send: &mut Option, -) -> io::Result<()> { - let mut mantissa_str = inter_rep.mantissa.to_string(); - - // Determine the position to insert the decimal point - let mut decimal_pos = mantissa_str.len() as i64 - inter_rep.exponent; - - // Handle cases where the decimal position is before the first digit - if decimal_pos <= 0 { - let zero_padding = "0".repeat(-decimal_pos as usize); - mantissa_str = format!("{}{}", zero_padding, mantissa_str); - decimal_pos = 1; // Decimal point will be at the first digit position - } - - // Convert to &str for split_at - let mantissa_str = mantissa_str.as_str(); - - // Insert the decimal point - let decimal_position = decimal_pos as usize; - let (integer_part, fractional_part) = if decimal_position > 0 { - mantissa_str.split_at(decimal_position) - } else { - ("0", mantissa_str) - }; - - let result = if inter_rep.sign { - format!("{}.{}", integer_part, fractional_part) - } else { - format!("-{}.{}", integer_part, fractional_part) - }; - - if let Some(file) = filepath_send.as_mut() { - // Write string to the file - file.write_all(result.as_bytes())?; - file.write_all(b"\n")?; - } else { - io::stdout().write_all(result.as_bytes())?; - io::stdout().write_all(b"\n")?; - } - - Ok(()) -} - -/// Converts a string representation of a fixed-point number to the intermediate representation. -/// -/// This function takes a string slice representing a fixed-point number and an exponent value, -/// determines the sign, constructs the mantissa, sets the exponent to the given value, and -/// constructs an `IntermediateRepresentation` containing the sign, mantissa, and exponent. -/// -/// # Arguments -/// -/// * `fixed_string` - A string slice containing the fixed-point number to be converted. -/// * `exp_int` - The exponent value for the fixed-point number. -/// -/// # Returns -/// -/// This function returns an `IntermediateRepresentation` containing the sign, mantissa, -/// and exponent of the fixed-point number. -/// -/// # Panics -/// -/// This function will panic if the input string cannot be parsed as a number. -fn from_fixed(fixed_string: &str, exp_int: i64) -> IntermediateRepresentation { - let sign = !fixed_string.starts_with('-'); - let fixed_trimmed = fixed_string.trim_start_matches('-'); - - let mantissa_string = fixed_trimmed.to_string(); - - IntermediateRepresentation { - sign, - mantissa: BigUint::from_str(&mantissa_string).expect("Invalid number"), - exponent: exp_int, - } -} - -/// Converts the intermediate representation to a fixed-point number string and writes it to a file or stdout. -/// -/// This function takes an `IntermediateRepresentation`, computes the scale factor based on -/// the negative exponent, converts the mantissa to a `BigInt` and multiplies by the scale factor, -/// constructs the fixed-point number string applying the sign, and writes the resulting string -/// to the specified file or stdout. -/// -/// # Arguments -/// -/// * `inter_rep` - The intermediate representation to be converted. -/// * `filepath_send` - A mutable reference to an optional `File` where the fixed-point -/// number string will be written. If `None`, the result is written to stdout. -/// -/// # Returns -/// -/// This function returns a `std::io::Result<()>` which is `Ok` if the operation -/// is successful, or an `Err` if an I/O error occurs while writing to the file. -fn to_fixed( - inter_rep: IntermediateRepresentation, - filepath_send: &mut Option, -) -> io::Result<()> { - // Negate exp - let neg_exponent = -inter_rep.exponent; - - // 10^-exp - let scale_factor = BigInt::from(10).pow(neg_exponent as u32); - - // Convert mantissa to BigInt - let mantissa_bigint = BigInt::from(inter_rep.mantissa); - - let mantissa_mult = mantissa_bigint * scale_factor; - - // Apply the sign - let signed_value = if inter_rep.sign { - mantissa_mult - } else { - -mantissa_mult - }; - - // Handle placement of decimal point - let mantissa_str = signed_value.to_string(); - let mantissa_len = mantissa_str.len(); - let adjusted_exponent = inter_rep.exponent + mantissa_len as i64; - - let string = if adjusted_exponent <= 0 { - // Handle case where the exponent indicates a number less than 1 - let zero_padding = "0".repeat(-adjusted_exponent as usize); - format!("0.{}{}", zero_padding, mantissa_str) - } else if adjusted_exponent as usize >= mantissa_len { - // Handle case where the exponent is larger than the length of the mantissa - format!( - "{}{}", - mantissa_str, - "0".repeat(adjusted_exponent as usize - mantissa_len) - ) - } else { - // Normal case - let integer_part = &mantissa_str[..adjusted_exponent as usize]; - let fractional_part = &mantissa_str[adjusted_exponent as usize..]; - format!("{}.{}", integer_part, fractional_part) - }; - - // Write the result to the file or stdout - if let Some(file) = filepath_send.as_mut() { - file.write_all(string.as_bytes())?; - file.write_all(b"\n")?; - } else { - io::stdout().write_all(string.as_bytes())?; - io::stdout().write_all(b"\n")?; - } - - Ok(()) -} - -/// Converts a string representation of a hexadecimal number to the intermediate representation. -/// -/// This function takes a string slice representing a hexadecimal number, -/// converts it to a `BigUint`, determines the sign, and constructs an -/// `IntermediateRepresentation` containing the sign, mantissa, and exponent. -/// -/// # Arguments -/// -/// * `hex_string` - A string slice containing the hexadecimal number to be converted. -/// -/// # Returns -/// -/// This function returns an `IntermediateRepresentation` containing the sign, mantissa, -/// and exponent of the hexadecimal number. -/// -/// # Panics -/// -/// This function will panic if the input string cannot be parsed as a hexadecimal number. - -fn from_hex(hex_string: &str, width: usize, float_or_fixed: NumType) -> IntermediateRepresentation { - // Convert the cleaned hexadecimal string to BigUint - let hex_value = BigUint::from_str_radix(hex_string, 16) - .expect("Invalid hexadecimal string"); - - // Determine if the value is negative based on the MSB - let sign_bit = BigUint::from(1u64) << (width - 1); - let sign = &hex_value & &sign_bit == BigUint::from(0u64); - - let mantissa = if sign { - hex_value - } else { - // Calculate the two's complement for negative values - let max_value = BigUint::from(1u64) << width; - &max_value - &hex_value - }; - - IntermediateRepresentation { - sign, - mantissa, - exponent: 0, - } -} - -/// Converts the intermediate representation to a hexadecimal string and writes it to a file or stdout. -/// -/// This function takes an `IntermediateRepresentation`, converts the mantissa to a hexadecimal string, -/// applies the sign, and writes the resulting string to the specified file or stdout. -/// -/// # Arguments -/// -/// * `inter_rep` - The intermediate representation to be converted. -/// * `filepath_send` - A mutable reference to an optional `File` where the hexadecimal string -/// will be written. If `None`, the result is written to stdout. -/// -/// # Returns -/// -/// This function returns a `std::io::Result<()>` which is `Ok` if the operation -/// is successful, or an `Err` if an I/O error occurs while writing to the file. - -fn to_hex( - inter_rep: IntermediateRepresentation, - filepath_send: &mut Option, -) -> io::Result<()> { - // Apply the sign - let hex_value = if inter_rep.sign { - inter_rep.mantissa.to_str_radix(16) - } else { - format!("-{}", inter_rep.mantissa.to_str_radix(16)) - }; - - // Write the result to the file or stdout - if let Some(file) = filepath_send.as_mut() { - file.write_all(hex_value.as_bytes())?; - file.write_all(b"\n")?; - } else { - io::stdout().write_all(hex_value.as_bytes())?; - io::stdout().write_all(b"\n")?; - } - - Ok(()) -} diff --git a/tools/data-conversion/src/results.txt b/tools/data-conversion/src/results.txt new file mode 100644 index 0000000000..40295c0078 --- /dev/null +++ b/tools/data-conversion/src/results.txt @@ -0,0 +1,7 @@ + +| Command | Mean [s] | Min [s] | Max [s] | Relative | +|-----------------------------|---------------|---------|---------|-------------| +| Intermediate Representation | 3.607 ± 0.056 | 3.569 | 3.752 | 2.91 ± 0.29 | +| Float Arithmetic | 1.323 ± 0.050 | 1.286 | 1.460 | 1.07 ± 0.11 | +| Bit Slicing | 1.239 ± 0.121 | 1.156 | 1.523 | 1.00 | + diff --git a/tools/data-conversion/src/u8vector.rs b/tools/data-conversion/src/u8vector.rs new file mode 100644 index 0000000000..1e4db8d456 --- /dev/null +++ b/tools/data-conversion/src/u8vector.rs @@ -0,0 +1,58 @@ +pub fn binary_to_u8_vec(binary: &str) -> Result, String> { + let mut padded_binary: String = binary.to_string(); + + // If the binary string length is not a multiple of 8, pad it with leading zeros + let padding = 8 - (padded_binary.len() % 8); + if padding != 8 { + padded_binary = "0".repeat(padding) + &padded_binary; + } + + let mut vec = Vec::new(); + + for i in (0..padded_binary.len()).step_by(8) { + let byte_str = &padded_binary[i..i + 8]; + match u8::from_str_radix(byte_str, 2) { + Ok(byte) => vec.push(byte), + Err(_) => return Err(String::from("Invalid binary string")), + } + } + + Ok(vec) +} + +pub fn hex_to_u8_vec(hex: &str) -> Result, String> { + let mut padded_hex = hex.to_string(); + + let padding = 2 - (padded_hex.len() % 2); + if padding != 2 { + padded_hex = "0".repeat(padding) + &padded_hex; + } + + let mut vec = Vec::new(); + + for i in (0..padded_hex.len()).step_by(2) { + let byte_str = &padded_hex[i..i + 8]; + match u8::from_str_radix(byte_str, 2){ + Ok(byte) => vec.push(byte), + Err(_) => return Err(String::from("Invalid binary string")), + } + } + Ok(vec) +} + + +pub fn decimal_to_u8_vec(decimal: &str) -> Result, String> { + let mut vec = Vec::new(); + + // Iterate over each character in the decimal string + for c in decimal.chars() { + // Check if the character is a digit + if let Some(digit) = c.to_digit(10) { + // Convert the digit (u32) to a u8 and push it to the vector + vec.push(digit as u8); + } else { + return Err(format!("Invalid character '{}' in decimal string", c)); + } + } + Ok(vec) +} \ No newline at end of file From 15f3cb6abb545930a01fd0bced200eb2a2cd72d8 Mon Sep 17 00:00:00 2001 From: Angelica Schell Date: Wed, 25 Sep 2024 09:01:06 -0400 Subject: [PATCH 15/15] worked on u8 vector -> ir, and edited hex and binary -> u8 vector functions --- tools/data-conversion/src/fast_track.rs | 361 +++++++++++++++++++++ tools/data-conversion/src/ir.rs | 18 +- tools/data-conversion/src/main.rs | 399 ++---------------------- tools/data-conversion/src/u8vector.rs | 55 ++-- 4 files changed, 430 insertions(+), 403 deletions(-) create mode 100644 tools/data-conversion/src/fast_track.rs diff --git a/tools/data-conversion/src/fast_track.rs b/tools/data-conversion/src/fast_track.rs new file mode 100644 index 0000000000..362f6e1092 --- /dev/null +++ b/tools/data-conversion/src/fast_track.rs @@ -0,0 +1,361 @@ +use std::fs::File; +use std::io::stdout; +use std::io::{self, Write}; + +/// Formats [to_format] properly for float values +pub fn format_binary(to_format: u64) -> String { + let binary_str = format!("{:064b}", to_format); + format!( + "{} {} {}", + &binary_str[0..1], // Sign bit + &binary_str[1..9], // Exponent + &binary_str[9..] // Significand + ) +} + +pub fn format_hex(to_format: u64) -> String { + format!("0x{:X}", to_format) +} + +/// Converts a string representation of a floating-point number to its binary +/// format and appends the result to the specified file. +/// +/// This function takes a string slice representing a floating-point number, +/// converts it to a 64-bit floating-point number (`f64`), then converts this +/// number to its binary representation. The binary representation is formatted +/// as a string and written to the specified file, followed by a newline. +/// +/// # Arguments +/// +/// * `float_string` - A string slice containing the floating-point number to be converted. +/// * `filepath_send` - A mutable reference to a `File` where the binary representation +/// will be appended. +/// +/// # Returns +/// +/// This function returns a `std::io::Result<()>` which is `Ok` if the operation +/// is successful, or an `Err` if an I/O error occurs while writing to the file. +/// +/// # Panics +/// +/// This function will panic if the input string cannot be parsed as a floating-point number. +pub fn float_to_binary( + float_string: &str, + filepath_send: &mut Option, +) -> std::io::Result<()> { + let float_of_string: f64; + // Convert string to float + match float_string.parse::() { + Ok(parsed_num) => float_of_string = parsed_num, + Err(_) => { + panic!("Failed to parse float from string") + } + } + + // Convert float to binary + let binary_of_float = float_of_string.to_bits(); + let formatted_binary_str = format_binary(binary_of_float); + + if let Some(file) = filepath_send.as_mut() { + file.write_all(formatted_binary_str.as_bytes())?; + file.write_all(b"\n")?; + } else { + stdout().write_all(formatted_binary_str.as_bytes())?; + stdout().write_all(b"\n")?; + } + + Ok(()) +} + +/// Converts a string representation of a hexadecimal number to its binary +/// format and appends the result to the specified file. +/// +/// This function takes a string slice representing a hexadecimal number, +/// converts it to a 64-bit integer (`u64`), then converts this number to its +/// binary representation. The binary representation is formatted as a string +/// and written to the specified file, followed by a newline. +/// +/// # Arguments +/// +/// * `hex_string` - A string slice containing the hexadecimal number to be converted. +/// * `filepath_send` - A mutable reference to a `File` where the binary representation +/// will be appended. +/// +/// # Returns +/// +/// This function returns a `std::io::Result<()>` which is `Ok` if the operation +/// is successful, or an `Err` if an I/O error occurs while writing to the file. +/// +/// # Error +/// +/// This function will panic if the input string cannot be parsed as a hexadecimal number. +/// +/// This does not differentiate between floating and fixed. It just treats any hex as an integer. +pub fn hex_to_binary( + hex_string: &str, + filepath_send: &mut Option, +) -> io::Result<()> { + // Convert hex to binary + let binary_of_hex = u64::from_str_radix(hex_string, 16) + .expect("Failed to parse hex string"); + + // Format nicely + let formatted_binary_str = format!("{:b}", binary_of_hex); + + // Write binary string to the file + + if let Some(file) = filepath_send.as_mut() { + // Write binary string to the file + file.write_all(formatted_binary_str.as_bytes())?; + file.write_all(b"\n")?; + } else { + stdout().write_all(formatted_binary_str.as_bytes())?; + stdout().write_all(b"\n")?; + } + + Ok(()) +} + +/// Converts a string representation of a binary number to its hexadecimal +/// format and appends the result to the specified file. +/// +/// This function takes a string slice representing a binary number, +/// converts it to a 64-bit integer (`u64`), then converts this number to its +/// hexadecimal representation. The hexadecimal representation is formatted +/// as a string and written to the specified file, followed by a newline. +/// +/// # Arguments +/// +/// * `binary_string` - A string slice containing the binary number to be converted. +/// * `filepath_send` - A mutable reference to a `File` where the hexadecimal representation +/// will be appended. +/// +/// # Returns +/// +/// This function returns a `std::io::Result<()>` which is `Ok` if the operation +/// is successful, or an `Err` if an I/O error occurs while writing to the file. +/// +/// # Panics +/// +/// This function will panic if the input string cannot be parsed as a binary number. +pub fn binary_to_hex( + binary_string: &str, + filepath_send: &mut Option, +) -> io::Result<()> { + let hex_of_binary = u64::from_str_radix(binary_string, 2) + .expect("Failed to parse binary string"); + + let formatted_hex_str = format_hex(hex_of_binary); + + if let Some(file) = filepath_send.as_mut() { + // Write binary string to the file + file.write_all(formatted_hex_str.as_bytes())?; + file.write_all(b"\n")?; + } else { + stdout().write_all(formatted_hex_str.as_bytes())?; + stdout().write_all(b"\n")?; + } + + Ok(()) +} + +/// Converts a string representation of a binary number to its floating-point +/// format and appends the result to the specified file. +/// +/// This function takes a string slice representing a binary number, +/// converts it to a 64-bit integer (`u64`), then interprets this integer as +/// the binary representation of a 64-bit floating-point number (`f64`). +/// The floating-point representation is formatted as a string and written +/// to the specified file, followed by a newline. +/// +/// # Arguments +/// +/// * `binary_string` - A string slice containing the binary number to be converted. +/// * `filepath_send` - A mutable reference to a `File` where the floating-point representation +/// will be appended. +/// +/// # Returns +/// +/// This function returns a `std::io::Result<()>` which is `Ok` if the operation +/// is successful, or an `Err` if an I/O error occurs while writing to the file. +/// +/// # Panics +/// +/// This function will panic if the input string cannot be parsed as a binary number. +pub fn binary_to_float( + binary_string: &str, + filepath_send: &mut Option, +) -> io::Result<()> { + let binary_value = u64::from_str_radix(binary_string, 2) + .expect("Failed to parse binary string"); + + let formated_float_str = format!("{:?}", binary_value); + + if let Some(file) = filepath_send.as_mut() { + // Write binary string to the file + file.write_all(formated_float_str.as_bytes())?; + file.write_all(b"\n")?; + } else { + stdout().write_all(formated_float_str.as_bytes())?; + stdout().write_all(b"\n")?; + } + + Ok(()) +} + +/// Converts a string representation of a fixed-point number to its binary +/// format and appends the result to the specified file. +/// +/// This function takes a string slice representing a fixed-point number, +/// multiplies it by 2 raised to the power of the negative exponent, converts the result +/// to a 64-bit integer, and then to its binary representation. The binary representation +/// is formatted as a string and written to the specified file, followed by a newline. +/// +/// # Arguments +/// +/// * `fixed_string` - A string slice containing the fixed-point number to be converted. +/// * `filepath_send` - A mutable reference to a `File` where the binary representation +/// will be appended. +/// * `exponent` - A floating-point number representing the exponent to be applied in the +/// conversion process. +/// +/// # Returns +/// +/// This function returns a `std::io::Result<()>` which is `Ok` if the operation +/// is successful, or an `Err` if an I/O error occurs while writing to the file. +/// +/// # Panics +/// +/// This function will panic if the input string cannot be parsed as a fixed-point number. +pub fn fixed_to_binary( + fixed_string: &str, + filepath_send: &mut Option, + exp_int: i64, +) -> io::Result<()> { + // Convert fixed value from string to int + let fixed_value: f64; + match fixed_string.parse::() { + Ok(parsed_num) => fixed_value = parsed_num, + Err(_) => { + panic!("Bad fixed value input") + } + } + + //exponent int to float so we can multiply + let exponent = exp_int as f64; + + // Exponent math + let multiplied_fixed = fixed_value * 2_f64.powf(-exponent); + + // Convert to a 64-bit integer + let multiplied_fixed_as_i64 = multiplied_fixed as i64; + + // Convert to a binary string with 64 bits + let binary_of_fixed = format!("{:064b}", multiplied_fixed_as_i64); + + if let Some(file) = filepath_send.as_mut() { + // Write binary string to the file + file.write_all(binary_of_fixed.as_bytes())?; + file.write_all(b"\n")?; + } else { + stdout().write_all(binary_of_fixed.as_bytes())?; + stdout().write_all(b"\n")?; + } + + Ok(()) +} + +/// Converts a string representation of a binary number to its fixed-point +/// format and appends the result to the specified file. +/// +/// This function takes a string slice representing a binary number, +/// converts it to a 64-bit unsigned integer, interprets this integer as +/// a floating-point number, divides it by 2 raised to the power of the negative exponent, +/// and converts the result to its fixed-point representation. The fixed-point +/// representation is formatted as a string and written to the specified file, +/// followed by a newline. +/// +/// # Arguments +/// +/// * `binary_string` - A string slice containing the binary number to be converted. +/// * `filepath_send` - A mutable reference to a `File` where the fixed-point representation +/// will be appended. +/// * `exponent` - A floating-point number representing the exponent to be applied in the +/// conversion process. +/// +/// # Returns +/// +/// This function returns a `std::io::Result<()>` which is `Ok` if the operation +/// is successful, or an `Err` if an I/O error occurs while writing to the file. +/// +/// # Panics +/// +/// This function will panic if the input string cannot be parsed as a binary number. +pub fn binary_to_fixed( + binary_string: &str, + filepath_send: &mut Option, + exp_int: i64, +) -> io::Result<()> { + // Convert binary value from string to int + let binary_value = match u64::from_str_radix(binary_string, 2) { + Ok(parsed_num) => parsed_num, + Err(_) => panic!("Bad binary value input"), + }; + + // Convert to fixed + let int_of_binary = binary_value as f64; + + //exponent int to float so we can multiply + let exponent = exp_int as f64; + + // Exponent math + let divided: f64 = int_of_binary / 2_f64.powf(-exponent); + + let string_of_divided = format!("{:+.8e}", divided); + + if let Some(file) = filepath_send.as_mut() { + // Write binary string to the file + file.write_all(string_of_divided.as_bytes())?; + file.write_all(b"\n")?; + } else { + stdout().write_all(string_of_divided.as_bytes())?; + stdout().write_all(b"\n")?; + } + + Ok(()) +} + +pub fn binary_to_fixed_bit_slice( + binary_string: &str, + filepath_send: &mut Option, + exp_int: i64, +) -> io::Result<()> { + // Convert binary string to an integer (assuming binary_string is a valid binary representation) + let binary_int = u64::from_str_radix(binary_string, 2).unwrap(); + + // Adjust the binary point based on the exponent + let mut result = binary_int; + if exp_int < 0 { + // If exponent is negative, shift right (multiply by 2^(-exp_int)) + result >>= -exp_int as u64; + } else { + // If exponent is positive, shift left (multiply by 2^(exp_int)) + result <<= exp_int as u64; + } + + // Convert result to a fixed-point decimal representation + let fixed_value = result as f64; + + let string_of_fixed = format!("{:.8e}", fixed_value); + + if let Some(file) = filepath_send.as_mut() { + // Write binary string to the file + file.write_all(string_of_fixed.as_bytes())?; + file.write_all(b"\n")?; + } else { + stdout().write_all(string_of_fixed.as_bytes())?; + stdout().write_all(b"\n")?; + } + + Ok(()) +} diff --git a/tools/data-conversion/src/ir.rs b/tools/data-conversion/src/ir.rs index f800c848dd..c451325102 100644 --- a/tools/data-conversion/src/ir.rs +++ b/tools/data-conversion/src/ir.rs @@ -6,10 +6,13 @@ use std::io::{self, Write}; use std::str::FromStr; +/// * 'sign' - `true` indicates that the value is negative; `false` indicates that it is positive. +/// * 'mantissa' - The absolute value represented as an integer without a decimal point. +/// * 'exponent' - The exponent to apply to the mantissa, where the actual value is calculated as `mantissa * 2^exponent`. The exponent can be negative. pub struct IntermediateRepresentation { - sign: bool, - mantissa: BigUint, - exponent: i64, + pub sign: bool, + pub mantissa: BigUint, + pub exponent: i64, } @@ -36,9 +39,16 @@ pub struct IntermediateRepresentation { pub fn from_binary( binary_string: &str, bit_width: usize, + twos_comp: bool, ) -> IntermediateRepresentation { - let sign = binary_string.starts_with('0'); + let sign; + if !twos_comp { + sign = false; + } else{ + sign = binary_string.starts_with('0'); + } + let binary_value = BigUint::from_str_radix(binary_string, 2) .expect("Invalid binary string"); diff --git a/tools/data-conversion/src/main.rs b/tools/data-conversion/src/main.rs index f8afa5cee6..1cf257d04d 100644 --- a/tools/data-conversion/src/main.rs +++ b/tools/data-conversion/src/main.rs @@ -1,33 +1,22 @@ use argh::FromArgs; -use num_bigint::BigUint; use std::error::Error; use std::fmt; use std::fs::read_to_string; use std::fs::File; -use std::io::stdout; -use std::io::{self, Write}; use std::str::FromStr; mod u8vector; mod ir; +mod fast_track; //cargo run -- --from $PATH1 --to $PATH2 --ftype "from" --totype "to" // Thresholds for using fast-track functions -const FAST_TRACK_THRESHOLD_BINARY_TO_FIXED: usize = 53; //52 bits for the significand (plus 1 implicit bit)b +// const FAST_TRACK_THRESHOLD_BINARY_TO_FIXED: usize = 53; //52 bits for the significand (plus 1 implicit bit)b +// const FAST_TRACK_THRESHOLD_FIXED_TO_BINARY: usize = 53; const FAST_TRACK_THRESHOLD_FLOAT_TO_BINARY: usize = 53; const FAST_TRACK_THRESHOLD_BINARY_TO_FLOAT: usize = 53; -const FAST_TRACK_THRESHOLD_FIXED_TO_BINARY: usize = 53; const FAST_TRACK_THRESHOLD_HEX_TO_BINARY: usize = 64; const FAST_TRACK_THRESHOLD_BINARY_TO_HEX: usize = 64; -/// * 'sign' - `true` indicates that the value is negative; `false` indicates that it is positive. -/// * 'mantissa' - The absolute value represented as an integer without a decimal point. -/// * 'exponent' - The exponent to apply to the mantissa, where the actual value is calculated as `mantissa * 2^exponent`. The exponent can be negative. -struct IntermediateRepresentation { - sign: bool, - mantissa: BigUint, - exponent: i64, -} - #[derive(Debug)] struct ParseNumTypeError; @@ -137,8 +126,8 @@ struct Arguments { #[argh(option)] tofile: FileType, - /// optional exponent for fixed_to_binary -> default is -1 - #[argh(option, default = "-1")] + /// optional exponent for fixed_to_binary -> default is -0 + #[argh(option, default = "0")] exp: i64, /// optional for fixed_to_binary using bit slicing. If choosen, will use bit slicing. @@ -151,7 +140,11 @@ struct Arguments { /// optional flag to force the inter-rep path #[argh(switch, short = 'i')] - inter: bool + inter: bool, + + /// optional flag - when flagged, will not use two's complement for binary + #[argh(switch, short = 't')] + twos: bool } fn main() { @@ -168,6 +161,7 @@ fn main() { args.bits, args.width, args.inter, + args.twos ); } @@ -199,6 +193,7 @@ fn convert( bits: bool, width: usize, inter: bool, + twos: bool ) { // Create the output file if filepath_send is Some let mut converted: Option = filepath_send @@ -211,7 +206,7 @@ fn convert( (FileType:: Hex, FileType::Binary) => { for line in read_to_string(filepath_get).unwrap().lines() { if line.len() <= FAST_TRACK_THRESHOLD_HEX_TO_BINARY && !inter{ - hex_to_binary(line, &mut converted) + fast_track::hex_to_binary(line, &mut converted) .expect("Failed to write binary to file"); } else { ir::to_binary(ir::from_hex(line, width), &mut converted, width) @@ -222,7 +217,7 @@ fn convert( (FileType:: Decimal, FileType::Binary)=>{ for line in read_to_string(filepath_get).unwrap().lines() { if line.len() <= FAST_TRACK_THRESHOLD_FLOAT_TO_BINARY && !inter { - float_to_binary(line, &mut converted) + fast_track::float_to_binary(line, &mut converted) .expect("Failed to write binary to file"); } else { ir::to_binary(ir::from_float(line), &mut converted, width) @@ -234,11 +229,11 @@ fn convert( for line in read_to_string(filepath_get).unwrap().lines() { print!("used fastpath"); if line.len() <= FAST_TRACK_THRESHOLD_BINARY_TO_HEX && !inter { - binary_to_hex(line, &mut converted) + fast_track::binary_to_hex(line, &mut converted) .expect("Failed to write hex to file"); } else { print!("used intermediate"); - ir::to_hex(ir::from_binary(line, width), &mut converted) + ir::to_hex(ir::from_binary(line, width, twos), &mut converted) .expect("Failed to write binary to file"); } } @@ -246,10 +241,10 @@ fn convert( (FileType:: Binary, FileType::Decimal)=>{ for line in read_to_string(filepath_get).unwrap().lines() { if line.len() <= FAST_TRACK_THRESHOLD_BINARY_TO_FLOAT && !inter { - binary_to_float(line, &mut converted) + fast_track::binary_to_float(line, &mut converted) .expect("Failed to write float to file"); } else { - ir::to_float(ir::from_binary(line, width), &mut converted) + ir::to_float(ir::from_binary(line, width, twos), &mut converted) .expect("Failed to write binary to file"); } } @@ -292,361 +287,3 @@ fn convert( ); } } - -/// Formats [to_format] properly for float values -fn format_binary(to_format: u64) -> String { - let binary_str = format!("{:064b}", to_format); - format!( - "{} {} {}", - &binary_str[0..1], // Sign bit - &binary_str[1..9], // Exponent - &binary_str[9..] // Significand - ) -} - -fn format_hex(to_format: u64) -> String { - format!("0x{:X}", to_format) -} - -/// Converts a string representation of a floating-point number to its binary -/// format and appends the result to the specified file. -/// -/// This function takes a string slice representing a floating-point number, -/// converts it to a 64-bit floating-point number (`f64`), then converts this -/// number to its binary representation. The binary representation is formatted -/// as a string and written to the specified file, followed by a newline. -/// -/// # Arguments -/// -/// * `float_string` - A string slice containing the floating-point number to be converted. -/// * `filepath_send` - A mutable reference to a `File` where the binary representation -/// will be appended. -/// -/// # Returns -/// -/// This function returns a `std::io::Result<()>` which is `Ok` if the operation -/// is successful, or an `Err` if an I/O error occurs while writing to the file. -/// -/// # Panics -/// -/// This function will panic if the input string cannot be parsed as a floating-point number. -fn float_to_binary( - float_string: &str, - filepath_send: &mut Option, -) -> std::io::Result<()> { - let float_of_string: f64; - // Convert string to float - match float_string.parse::() { - Ok(parsed_num) => float_of_string = parsed_num, - Err(_) => { - panic!("Failed to parse float from string") - } - } - - // Convert float to binary - let binary_of_float = float_of_string.to_bits(); - let formatted_binary_str = format_binary(binary_of_float); - - if let Some(file) = filepath_send.as_mut() { - file.write_all(formatted_binary_str.as_bytes())?; - file.write_all(b"\n")?; - } else { - stdout().write_all(formatted_binary_str.as_bytes())?; - stdout().write_all(b"\n")?; - } - - Ok(()) -} - -/// Converts a string representation of a hexadecimal number to its binary -/// format and appends the result to the specified file. -/// -/// This function takes a string slice representing a hexadecimal number, -/// converts it to a 64-bit integer (`u64`), then converts this number to its -/// binary representation. The binary representation is formatted as a string -/// and written to the specified file, followed by a newline. -/// -/// # Arguments -/// -/// * `hex_string` - A string slice containing the hexadecimal number to be converted. -/// * `filepath_send` - A mutable reference to a `File` where the binary representation -/// will be appended. -/// -/// # Returns -/// -/// This function returns a `std::io::Result<()>` which is `Ok` if the operation -/// is successful, or an `Err` if an I/O error occurs while writing to the file. -/// -/// # Error -/// -/// This function will panic if the input string cannot be parsed as a hexadecimal number. -/// -/// This does not differentiate between floating and fixed. It just treats any hex as an integer. -fn hex_to_binary( - hex_string: &str, - filepath_send: &mut Option, -) -> io::Result<()> { - // Convert hex to binary - let binary_of_hex = u64::from_str_radix(hex_string, 16) - .expect("Failed to parse hex string"); - - // Format nicely - let formatted_binary_str = format!("{:b}", binary_of_hex); - - // Write binary string to the file - - if let Some(file) = filepath_send.as_mut() { - // Write binary string to the file - file.write_all(formatted_binary_str.as_bytes())?; - file.write_all(b"\n")?; - } else { - stdout().write_all(formatted_binary_str.as_bytes())?; - stdout().write_all(b"\n")?; - } - - Ok(()) -} - -/// Converts a string representation of a binary number to its hexadecimal -/// format and appends the result to the specified file. -/// -/// This function takes a string slice representing a binary number, -/// converts it to a 64-bit integer (`u64`), then converts this number to its -/// hexadecimal representation. The hexadecimal representation is formatted -/// as a string and written to the specified file, followed by a newline. -/// -/// # Arguments -/// -/// * `binary_string` - A string slice containing the binary number to be converted. -/// * `filepath_send` - A mutable reference to a `File` where the hexadecimal representation -/// will be appended. -/// -/// # Returns -/// -/// This function returns a `std::io::Result<()>` which is `Ok` if the operation -/// is successful, or an `Err` if an I/O error occurs while writing to the file. -/// -/// # Panics -/// -/// This function will panic if the input string cannot be parsed as a binary number. -fn binary_to_hex( - binary_string: &str, - filepath_send: &mut Option, -) -> io::Result<()> { - let hex_of_binary = u64::from_str_radix(binary_string, 2) - .expect("Failed to parse binary string"); - - let formatted_hex_str = format_hex(hex_of_binary); - - if let Some(file) = filepath_send.as_mut() { - // Write binary string to the file - file.write_all(formatted_hex_str.as_bytes())?; - file.write_all(b"\n")?; - } else { - stdout().write_all(formatted_hex_str.as_bytes())?; - stdout().write_all(b"\n")?; - } - - Ok(()) -} - -/// Converts a string representation of a binary number to its floating-point -/// format and appends the result to the specified file. -/// -/// This function takes a string slice representing a binary number, -/// converts it to a 64-bit integer (`u64`), then interprets this integer as -/// the binary representation of a 64-bit floating-point number (`f64`). -/// The floating-point representation is formatted as a string and written -/// to the specified file, followed by a newline. -/// -/// # Arguments -/// -/// * `binary_string` - A string slice containing the binary number to be converted. -/// * `filepath_send` - A mutable reference to a `File` where the floating-point representation -/// will be appended. -/// -/// # Returns -/// -/// This function returns a `std::io::Result<()>` which is `Ok` if the operation -/// is successful, or an `Err` if an I/O error occurs while writing to the file. -/// -/// # Panics -/// -/// This function will panic if the input string cannot be parsed as a binary number. -fn binary_to_float( - binary_string: &str, - filepath_send: &mut Option, -) -> io::Result<()> { - let binary_value = u64::from_str_radix(binary_string, 2) - .expect("Failed to parse binary string"); - - let formated_float_str = format!("{:?}", binary_value); - - if let Some(file) = filepath_send.as_mut() { - // Write binary string to the file - file.write_all(formated_float_str.as_bytes())?; - file.write_all(b"\n")?; - } else { - stdout().write_all(formated_float_str.as_bytes())?; - stdout().write_all(b"\n")?; - } - - Ok(()) -} - -/// Converts a string representation of a fixed-point number to its binary -/// format and appends the result to the specified file. -/// -/// This function takes a string slice representing a fixed-point number, -/// multiplies it by 2 raised to the power of the negative exponent, converts the result -/// to a 64-bit integer, and then to its binary representation. The binary representation -/// is formatted as a string and written to the specified file, followed by a newline. -/// -/// # Arguments -/// -/// * `fixed_string` - A string slice containing the fixed-point number to be converted. -/// * `filepath_send` - A mutable reference to a `File` where the binary representation -/// will be appended. -/// * `exponent` - A floating-point number representing the exponent to be applied in the -/// conversion process. -/// -/// # Returns -/// -/// This function returns a `std::io::Result<()>` which is `Ok` if the operation -/// is successful, or an `Err` if an I/O error occurs while writing to the file. -/// -/// # Panics -/// -/// This function will panic if the input string cannot be parsed as a fixed-point number. -fn fixed_to_binary( - fixed_string: &str, - filepath_send: &mut Option, - exp_int: i64, -) -> io::Result<()> { - // Convert fixed value from string to int - let fixed_value: f64; - match fixed_string.parse::() { - Ok(parsed_num) => fixed_value = parsed_num, - Err(_) => { - panic!("Bad fixed value input") - } - } - - //exponent int to float so we can multiply - let exponent = exp_int as f64; - - // Exponent math - let multiplied_fixed = fixed_value * 2_f64.powf(-exponent); - - // Convert to a 64-bit integer - let multiplied_fixed_as_i64 = multiplied_fixed as i64; - - // Convert to a binary string with 64 bits - let binary_of_fixed = format!("{:064b}", multiplied_fixed_as_i64); - - if let Some(file) = filepath_send.as_mut() { - // Write binary string to the file - file.write_all(binary_of_fixed.as_bytes())?; - file.write_all(b"\n")?; - } else { - stdout().write_all(binary_of_fixed.as_bytes())?; - stdout().write_all(b"\n")?; - } - - Ok(()) -} - -/// Converts a string representation of a binary number to its fixed-point -/// format and appends the result to the specified file. -/// -/// This function takes a string slice representing a binary number, -/// converts it to a 64-bit unsigned integer, interprets this integer as -/// a floating-point number, divides it by 2 raised to the power of the negative exponent, -/// and converts the result to its fixed-point representation. The fixed-point -/// representation is formatted as a string and written to the specified file, -/// followed by a newline. -/// -/// # Arguments -/// -/// * `binary_string` - A string slice containing the binary number to be converted. -/// * `filepath_send` - A mutable reference to a `File` where the fixed-point representation -/// will be appended. -/// * `exponent` - A floating-point number representing the exponent to be applied in the -/// conversion process. -/// -/// # Returns -/// -/// This function returns a `std::io::Result<()>` which is `Ok` if the operation -/// is successful, or an `Err` if an I/O error occurs while writing to the file. -/// -/// # Panics -/// -/// This function will panic if the input string cannot be parsed as a binary number. -fn binary_to_fixed( - binary_string: &str, - filepath_send: &mut Option, - exp_int: i64, -) -> io::Result<()> { - // Convert binary value from string to int - let binary_value = match u64::from_str_radix(binary_string, 2) { - Ok(parsed_num) => parsed_num, - Err(_) => panic!("Bad binary value input"), - }; - - // Convert to fixed - let int_of_binary = binary_value as f64; - - //exponent int to float so we can multiply - let exponent = exp_int as f64; - - // Exponent math - let divided: f64 = int_of_binary / 2_f64.powf(-exponent); - - let string_of_divided = format!("{:+.8e}", divided); - - if let Some(file) = filepath_send.as_mut() { - // Write binary string to the file - file.write_all(string_of_divided.as_bytes())?; - file.write_all(b"\n")?; - } else { - stdout().write_all(string_of_divided.as_bytes())?; - stdout().write_all(b"\n")?; - } - - Ok(()) -} - -fn binary_to_fixed_bit_slice( - binary_string: &str, - filepath_send: &mut Option, - exp_int: i64, -) -> io::Result<()> { - // Convert binary string to an integer (assuming binary_string is a valid binary representation) - let binary_int = u64::from_str_radix(binary_string, 2).unwrap(); - - // Adjust the binary point based on the exponent - let mut result = binary_int; - if exp_int < 0 { - // If exponent is negative, shift right (multiply by 2^(-exp_int)) - result >>= -exp_int as u64; - } else { - // If exponent is positive, shift left (multiply by 2^(exp_int)) - result <<= exp_int as u64; - } - - // Convert result to a fixed-point decimal representation - let fixed_value = result as f64; - - let string_of_fixed = format!("{:.8e}", fixed_value); - - if let Some(file) = filepath_send.as_mut() { - // Write binary string to the file - file.write_all(string_of_fixed.as_bytes())?; - file.write_all(b"\n")?; - } else { - stdout().write_all(string_of_fixed.as_bytes())?; - stdout().write_all(b"\n")?; - } - - Ok(()) -} diff --git a/tools/data-conversion/src/u8vector.rs b/tools/data-conversion/src/u8vector.rs index 1e4db8d456..3083ce3614 100644 --- a/tools/data-conversion/src/u8vector.rs +++ b/tools/data-conversion/src/u8vector.rs @@ -1,10 +1,14 @@ +use crate::ir::IntermediateRepresentation; +use num_bigint::{BigUint, BigInt}; + pub fn binary_to_u8_vec(binary: &str) -> Result, String> { - let mut padded_binary: String = binary.to_string(); + let mut padded_binary = binary.to_string(); - // If the binary string length is not a multiple of 8, pad it with leading zeros + // If the binary string length is not a multiple of 8, pad with the most significant bit let padding = 8 - (padded_binary.len() % 8); if padding != 8 { - padded_binary = "0".repeat(padding) + &padded_binary; + let msb = &padded_binary[0..1]; // Get the most significant bit + padded_binary = msb.repeat(padding) + &padded_binary; // Pad with the MSB } let mut vec = Vec::new(); @@ -20,39 +24,54 @@ pub fn binary_to_u8_vec(binary: &str) -> Result, String> { Ok(vec) } + pub fn hex_to_u8_vec(hex: &str) -> Result, String> { let mut padded_hex = hex.to_string(); + // If the hex string length is not a multiple of 2, pad with the most significant nibble let padding = 2 - (padded_hex.len() % 2); if padding != 2 { - padded_hex = "0".repeat(padding) + &padded_hex; + let msb = &padded_hex[0..1]; // Get the most significant nibble + padded_hex = msb.repeat(padding) + &padded_hex; // Pad with the MSB } let mut vec = Vec::new(); for i in (0..padded_hex.len()).step_by(2) { - let byte_str = &padded_hex[i..i + 8]; - match u8::from_str_radix(byte_str, 2){ + let byte_str = &padded_hex[i..i + 2]; // Fixed to extract two hex digits + match u8::from_str_radix(byte_str, 16) { Ok(byte) => vec.push(byte), - Err(_) => return Err(String::from("Invalid binary string")), + Err(_) => return Err(String::from("Invalid hex string")), } } Ok(vec) } -pub fn decimal_to_u8_vec(decimal: &str) -> Result, String> { - let mut vec = Vec::new(); - // Iterate over each character in the decimal string - for c in decimal.chars() { - // Check if the character is a digit - if let Some(digit) = c.to_digit(10) { - // Convert the digit (u32) to a u8 and push it to the vector - vec.push(digit as u8); - } else { - return Err(format!("Invalid character '{}' in decimal string", c)); +pub fn u8_to_ir(vector: Result, String>, exponent: i64) -> IntermediateRepresentation { + match vector { + Ok(vec) => { + // Check if the MSB of the first byte is 1 + let is_negative = (vec[0] & 0b10000000) != 0; + + let mantissa = if is_negative { + // Convert the Vec to a two's complement BigInt, then get its absolute value + let bigint = BigInt::from_signed_bytes_be(&vec); + bigint.magnitude().clone() // absolute value + } else { + BigUint::from_bytes_be(&vec) + }; + + IntermediateRepresentation { + sign: is_negative, + mantissa, + exponent, + } + } + Err(e) => { + // Handle the error case, for example by panicking or returning a default value. + panic!("Failed to convert: {}", e); } } - Ok(vec) } \ No newline at end of file