diff --git a/tools/data-conversion/src/ir.rs b/tools/data-conversion/src/ir.rs index 1e4db8d45..f800c848d 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 3811f3f74..f8afa5cee 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 000000000..40295c007 --- /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 000000000..1e4db8d45 --- /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