/********************************************************************************************************* * ------------------------------------------------------------------------------------------------------ * file description * ------------------------------------------------------------------------------------------------------ * \file intl.c * \unit intl * \brief This is a simple large inter number calculate module for C language * \author Lamdonn * \version v1.0.0 * \license GPL-2.0 * \copyright Copyright (C) 2023 Lamdonn. ********************************************************************************************************/ #include "intl.h" /* Internal static function declarations */ static int intl_ucmp(intl a, intl b); static intl intl_umul(intl a, intl b); static intl intl_udiv(intl a, intl b, intl *mod); static intl intl_umod(intl a, intl b); /** * \brief Adds two intl numbers. * * This function computes the sum of two 128-bit integers * (intl). It processes each 16-bit part of the input integers, * handling carry bits as necessary. The result is stored in a * new intl number. This function ensures that overflow is * correctly managed across all parts. * * \param[in] a: The first operand (intl number). * \param[in] b: The second operand (intl number). * \return The sum of a and b as an intl (128-bit integer). */ intl intl_add(intl a, intl b) { intl result; // Initialize the result variable uint16_t carry = 0; /** Carry bit */ // Perform addition for each 16-bit part for (int i = 0; i < INTL_U16_PARTS; i++) { // Calculate the sum of corresponding parts and carry uint32_t sum = (uint32_t)a.u16[i] + (uint32_t)b.u16[i] + carry; result.u16[i] = (uint16_t)(sum & 0xFFFF); /** Lower 16 bits */ carry = (sum >> 16) & 0xFFFF; /** Upper 16 bits as carry */ } return result; // Return the resulting intl number } /** * \brief Subtracts one intl number from another. * * This function computes the difference of two 128-bit integers * (intl). It processes each 16-bit part of the minuend and * subtrahend, handling borrow bits as necessary. The result is * stored in a new intl number. This function ensures that * borrowing is correctly managed across all parts. * * \param[in] a: The minuend (the number from which another is to be subtracted). * \param[in] b: The subtrahend (the number to be subtracted). * \return The result of a - b as an intl (128-bit integer). */ intl intl_sub(intl a, intl b) { intl result; // Initialize the result variable // Perform subtraction for each 16-bit part for (int i = 0; i < INTL_U16_PARTS; i++) { uint32_t diff = (uint32_t)a.u16[i] - (uint32_t)b.u16[i]; // Check if a borrow occurred if (diff & 0xFFFF0000) /** Borrow occurred */ { // Adjust the higher parts to account for the borrow for (int j = i + 1; j < INTL_U16_PARTS; j++) { a.u16[j] -= 1; // Borrow from the next part if (a.u16[j] != 0xFFFF) break; // Stop if no further borrow needed } } // Store the result of the subtraction result.u16[i] = (uint16_t)(diff & 0xFFFF); } return result; // Return the resulting intl number } /** * \brief Increments the intl number by one. * * This function increments a 128-bit integer (intl) by one. * It processes each 32-bit part of the input integer and * handles carry bits as necessary. The function continues * to increment the subsequent parts until there is no overflow. * * \param[in] a: The intl number to increment. * \return The incremented intl number as an intl (128-bit integer). */ intl intl_inc(intl a) { // Increment each 32-bit part of the intl number for (int i = 0; i < INTL_U32_PARTS; i++) { a.u32[i]++; // Increment the current part // Check if the current part overflowed if (a.u32[i] != 0) { break; /** Return immediately if no overflow */ } } return a; /** Return the incremented result */ } /** * \brief Decrements the intl number by one. * * This function decrements a 128-bit integer (intl) by one. * It processes each 32-bit part of the input integer, handling * borrowing as necessary. If the current part is zero, it sets * that part to its maximum value (0xFFFFFFFF) and continues * to the next part to borrow from it. * * \param[in] a: The intl number to decrement. * \return The decremented intl number as an intl (128-bit integer). */ intl intl_dec(intl a) { // Decrement each 32-bit part of the intl number for (int i = 0; i < INTL_U32_PARTS; i++) { // Check if the current part can be decremented if (a.u32[i] != 0) { a.u32[i]--; // Decrement the current part break; /** Return immediately if current part can be decremented */ } // If current part is zero, set it to max value and continue borrowing a.u32[i] = 0xFFFFFFFF; } return a; /** Return the decremented result */ } /** * \brief Multiplies two intl unsigned numbers. * * This function performs multiplication of two 128-bit unsigned integers * (intl) by using a method similar to the schoolbook algorithm. The * multiplication is carried out by breaking the numbers into their * 16-bit components and accumulating the results. The function handles * carry-over during the multiplication and addition stages to ensure * the final product is accurately represented. * * \param[in] a: The first operand to multiply. * \param[in] b: The second operand to multiply. * \return The product of a and b as an intl (128-bit unsigned integer). */ static intl intl_umul(intl a, intl b) { intl result = {0}; /** Initialize the result to 0 */ intl temp[INTL_U16_PARTS] = {{0}}; // Temporary storage for intermediate results uint16_t carry = 0; // Variable to hold carry-over during multiplication // Perform multiplication for (int i = 0; i < INTL_U16_PARTS; i++) { carry = 0; // Reset carry for the current row for (int j = 0; j < INTL_U16_PARTS; j++) { if (i + j < INTL_U16_PARTS) { // Multiply the 16-bit segments and add carry uint32_t mul = (uint32_t)a.u16[i] * (uint32_t)b.u16[j] + carry; temp[i].u16[i + j] = (mul & 0xFFFF); // Store the lower 16 bits carry = ((mul >> 16) & 0xFFFF); // Update carry for the next addition } } } carry = 0; // Reset carry for the addition phase // Combine results from the temporary storage for (int i = 0; i < INTL_U16_PARTS; i++) { uint32_t add = 0; // Variable to hold the sum of the current column for (int j = 0; j < INTL_U16_PARTS; j++) { add += temp[j].u16[i]; // Accumulate results from temp } add += carry; // Add any carry from the previous column result.u16[i] = (add & 0xFFFF); // Store the lower 16 bits in result carry = ((add >> 16) & 0xFFFF); // Update carry for the next column } return result; // Return the final product } /** * \brief Multiplies two intl numbers. * * This function multiplies two 128-bit integers (intl) and returns * the product as another intl number. It handles signed multiplication * by checking the sign of the operands. If either operand is negative, * it negates the operand and adjusts the sign of the result accordingly. * The actual multiplication is performed using the `intl_umul` * function, which handles the absolute values of the integers. * * \param[in] a: The first operand to multiply. * \param[in] b: The second operand to multiply. * \return The product of a and b as an intl (128-bit integer). */ intl intl_mul(intl a, intl b) { intl result = {0}; // Initialize the result to 0 int sign = 1; // Variable to track the sign of the result // Check and handle the sign of the first operand if (a.u32[INTL_U32_PARTS - 1] & 0x80000000) { sign = -sign; // Negate the sign for the result a = intl_neg(a); // Negate the first operand } // Check and handle the sign of the second operand if (b.u32[INTL_U32_PARTS - 1] & 0x80000000) { sign = -sign; // Negate the sign for the result b = intl_neg(b); // Negate the second operand } // Perform unsigned multiplication result = intl_umul(a, b); // If the result should be negative, negate it if (sign < 0) result = intl_neg(result); return result; // Return the final product } /** * \brief Divides one intl unsigned number by another. * * This function performs division of one 128-bit unsigned integer (intl) * by another. It calculates the quotient using a bitwise approach, * handling division by zero gracefully. The result is built bit by bit * from the most significant bit to the least significant bit. If the * divisor is zero, it prints an error message and returns zero. * * \param[in] a: The dividend (number to be divided). * \param[in] b: The divisor (number to divide by). * \return The quotient of a divided by b as an intl (128-bit unsigned integer). */ static intl intl_udiv(intl a, intl b, intl *mod) { // Check for division by zero if (intl_sign(b) == 0) { printf("Division by zero!\n"); return (intl){0}; /** Handle division by zero */ } intl result = {0}; // Initialize the result to zero intl remainder = {0}; // Initialize the remainder to zero /** Calculate bit by bit from the highest bit */ for (int i = INTL_BIT_PARTS - 1; i >= 0; i--) { /** Left shift remainder and add current bit */ remainder = intl_shl(remainder, 1); // Shift remainder left by 1 remainder.u32[0] |= (a.u32[i / 32] >> (i % 32)) & 1; // Add current bit from dividend /** If remainder is greater than or equal to b, subtract b */ if (intl_ucmp(remainder, b) >= 0) { remainder = intl_sub(remainder, b); // Subtract b from remainder result.u32[i / 32] |= (1 << (i % 32)); // Set corresponding bit in result } } if (mod) *mod = remainder; return result; // Return the final quotient } /** * \brief Divides one intl number by another. * * This function performs division of two 128-bit integers (intl) * and returns the quotient as another intl number. It handles signed * division by checking the sign of the operands. If either operand * is negative, it negates the operand and adjusts the sign of the * result accordingly. The actual division is performed using the * `intl_udiv` function, which handles the absolute values of * the integers. * * \param[in] a: The dividend (number to be divided). * \param[in] b: The divisor (number to divide by). * \return The quotient of a divided by b as an intl (128-bit integer). */ intl intl_div(intl a, intl b) { intl result = {0}; // Initialize the result to 0 int sign = 1; // Variable to track the sign of the result // Check and handle the sign of the dividend if (a.u32[INTL_U32_PARTS - 1] & 0x80000000) { sign = -sign; // Negate the sign for the result a = intl_neg(a); // Negate the dividend } // Check and handle the sign of the divisor if (b.u32[INTL_U32_PARTS - 1] & 0x80000000) { sign = -sign; // Negate the sign for the result b = intl_neg(b); // Negate the divisor } // Perform unsigned division result = intl_udiv(a, b, NULL); // If the result should be negative, negate it if (sign < 0) result = intl_neg(result); return result; // Return the final quotient } /** * \brief Computes the remainder of the division of two unsigned intl numbers. * * This function calculates the remainder of the division of two * 128-bit unsigned integers (intl). It uses a bitwise approach to * compute the remainder by processing each bit from the most significant * to the least significant. If the divisor is zero, it handles the * error gracefully by printing a message and returning zero. * * \param[in] a: The dividend (number to be divided). * \param[in] b: The divisor (number to divide by). * \return The remainder of a divided by b as an intl (128-bit unsigned integer). */ static intl intl_umod(intl a, intl b) { intl mod = {0}; intl_udiv(a, b, &mod); return mod; } /** * \brief Computes the remainder of the division of two intl numbers. * * This function calculates the remainder of the division of two * 128-bit integers (intl). It handles signed integers by checking * the sign of the dividend. If the dividend is negative, it negates * the dividend before performing the unsigned modulus operation. * The sign of the result is adjusted based on the sign of the * dividend. The actual remainder calculation is performed using the * `intl_umod` function, which handles the absolute values of * the integers. * * \param[in] a: The dividend (number to be divided). * \param[in] b: The divisor (number to divide by). * \return The remainder of a divided by b as an intl (128-bit integer). */ intl intl_mod(intl a, intl b) { intl result = {0}; // Initialize result to zero int sign = 1; // Variable to track the sign of the result // Check and handle the sign of the dividend if (a.u32[INTL_U32_PARTS - 1] & 0x80000000) { sign = -sign; // Negate the sign for the result a = intl_neg(a); // Negate the dividend } // Perform unsigned modulus with the absolute value of the divisor result = intl_umod(a, intl_abs(b)); // If the result should be negative, negate it if (sign < 0) result = intl_neg(result); return result; // Return the final remainder } /** * \brief Left shifts an intl number by a specified number of bits. * * This function performs a left bitwise shift on a 128-bit integer * (intl). The shift amount can be greater than 32 bits, in which case * the function calculates how many whole 32-bit parts to shift and * how many bits to shift within the remaining part. It constructs * the result based on the input number after applying the shift. * * \param[in] a: The intl number to shift. * \param[in] amount: The number of bits to shift to the left. * \return The left-shifted intl number. */ intl intl_shl(intl a, uint32_t amount) { intl result = {0}; // Initialize the result to zero int u32bias = amount / 32; // Number of whole 32-bit parts to shift int bitsbias = amount % 32; // Remaining bits to shift // Perform the shift for each 32-bit part of the intl number for (int i = 0; i < INTL_U32_PARTS; i++) { if (i < u32bias) { result.u32[i] = 0; // Set shifted-out parts to zero } else { // Shift the current part and add bits from the previous part if needed result.u32[i] = (a.u32[i - u32bias] << bitsbias) | (((i - u32bias - 1) >= 0 && bitsbias > 0) ? (a.u32[i - u32bias - 1] >> (32 - bitsbias)) : 0); } } return result; // Return the left-shifted result } /** * \brief Right shifts an intl number by a specified number of bits. * * This function performs a right bitwise shift on a 128-bit integer * (intl). The shift amount can be greater than 32 bits, in which case * the function calculates how many whole 32-bit parts to shift and * how many bits to shift within the remaining part. It constructs * the result based on the input number after applying the shift. * The sign bit is preserved for signed shifts. * * \param[in] a: The intl number to shift. * \param[in] amount: The number of bits to shift to the right. * \return The right-shifted intl number. */ intl intl_shr(intl a, uint32_t amount) { intl result = {0}; // Initialize the result to zero int u32bias = amount / 32; // Number of whole 32-bit parts to shift int bitsbias = amount % 32; // Remaining bits to shift // Perform the shift for each 32-bit part of the intl number for (int i = 0; i < INTL_U32_PARTS; i++) { // Check if the current index is beyond the range for valid shifts if (i > INTL_U32_PARTS - u32bias - 1 && INTL_U32_PARTS - u32bias - 1 > 0) { result.u32[i] = 0; // Set shifted-out parts to zero } else { // Shift the current part and add bits from the next part if needed result.u32[i] = (a.u32[i + u32bias] >> bitsbias) | (((i + u32bias + 1) < INTL_U32_PARTS && bitsbias > 0) ? (a.u32[i + u32bias + 1] << (32 - bitsbias)) : ((a.u32[INTL_U32_PARTS - 1] & 0x80000000) ? 0xFFFFFFFF : 0)); } } return result; // Return the right-shifted result } /** * \brief Performs bitwise AND operation on two intl numbers. * * This function computes the bitwise AND of two 128-bit integers * (intl). It processes each 32-bit part of the input integers and * performs the AND operation on corresponding parts, storing the * result in a new intl number. This operation yields a number that * has bits set only where both operands have bits set. * * \param[in] a: The first operand (intl number). * \param[in] b: The second operand (intl number). * \return The result of a AND b as an intl (128-bit integer). */ intl intl_and(intl a, intl b) { intl result; // Initialize the result variable // Perform the bitwise AND operation for each 32-bit part for (int i = 0; i < INTL_U32_PARTS; i++) { result.u32[i] = a.u32[i] & b.u32[i]; // Compute AND for each part } return result; // Return the resulting intl number } /** * \brief Performs bitwise OR operation on two intl numbers. * * This function computes the bitwise OR of two 128-bit integers * (intl). It processes each 32-bit part of the input integers and * performs the OR operation on corresponding parts, storing the * result in a new intl number. This operation yields a number that * has bits set where at least one of the operands has bits set. * * \param[in] a: The first operand (intl number). * \param[in] b: The second operand (intl number). * \return The result of a OR b as an intl (128-bit integer). */ intl intl_or(intl a, intl b) { intl result; // Initialize the result variable // Perform the bitwise OR operation for each 32-bit part for (int i = 0; i < INTL_U32_PARTS; i++) { result.u32[i] = a.u32[i] | b.u32[i]; // Compute OR for each part } return result; // Return the resulting intl number } /** * \brief Performs bitwise XOR operation on two intl numbers. * * This function computes the bitwise XOR of two 128-bit integers * (intl). It processes each 32-bit part of the input integers and * performs the XOR operation on corresponding parts, storing the * result in a new intl number. This operation yields a number that * has bits set where only one of the operands has bits set. * * \param[in] a: The first operand (intl number). * \param[in] b: The second operand (intl number). * \return The result of a XOR b as an intl (128-bit integer). */ intl intl_xor(intl a, intl b) { intl result; // Initialize the result variable // Perform the bitwise XOR operation for each 32-bit part for (int i = 0; i < INTL_U32_PARTS; i++) { result.u32[i] = a.u32[i] ^ b.u32[i]; // Compute XOR for each part } return result; // Return the resulting intl number } /** * \brief Performs bitwise NOT operation on an intl number. * * This function computes the bitwise NOT (negation) of a 128-bit * integer (intl). It processes each 32-bit part of the input integer * and applies the NOT operation, storing the result in a new intl * number. This operation inverts all bits of the input number. * * \param[in] a: The intl number to negate. * \return The bitwise negation of a as an intl (128-bit integer). */ intl intl_not(intl a) { intl result; // Initialize the result variable // Perform the bitwise NOT operation for each 32-bit part for (int i = 0; i < INTL_U32_PARTS; i++) { result.u32[i] = ~a.u32[i]; // Compute NOT for each part } return result; // Return the resulting intl number } /** * \brief Computes the absolute value of an intl number. * * This function checks if the given 128-bit unsigned integer (intl) * represents a negative value in two's complement representation. * If the most significant bit (sign bit) of the highest 32-bit segment * is set, it indicates a negative number, and the function calls * intl_neg to return its positive equivalent. If the number is * already non-negative, it simply returns the original number. * * \param[in] a: The intl number for which to compute the absolute value. * \return The absolute value of the intl number a. */ intl intl_abs(intl a) { // Check if the sign bit of the highest 32-bit part is set if (a.u32[INTL_U32_PARTS - 1] & 0x80000000) return intl_neg(a); // Return negated value if negative return a; // Return the original value if non-negative } /** * \brief Converts a string to an intl number. * * This function converts a string representation of a number * in various bases (decimal, binary, octal, hexadecimal) * into a 128-bit integer (intl). It handles optional signs * and base prefixes, and processes the string from the end to * the start for efficiency in base conversions. * * \param[in] str: The string to convert. * \return The converted intl number. Returns zero if the * string is invalid or represents zero. */ intl intl_from(const char *str) { const uint8_t ttable[4] = {10, 2, 8, 16}; // Table of digit limits for each base const uint8_t btable[4] = {0, 1, 3, 4}; // Table of bit shifts for each base uint32_t type = 0; // 0 - decimal, 1 - binary, 2 - octal, 3 - hexadecimal intl result = {0}; // Resulting intl number intl base = intl(1); /** Base initialized to 1 */ int sign = 1; // Sign of the number (1 for positive, -1 for negative) const char *p = str; // Pointer to traverse the input string // Determine the number type based on the string prefix switch (*p) { case '0': { if (p[1] == 0) { return (intl){0}; } // Handle case of "0" else if (p[1] == 'x' || p[1] == 'X') type = 3; // Hexadecimal else if (p[1] == 'o' || p[1] == 'O') type = 2; // Octal else if (p[1] == 'b' || p[1] == 'B') type = 1; // Binary else if (p[1] < '0' || p[1] >= '0' + ttable[type]) return (intl){0}; p += 2; // Move past the prefix } break; case '-': { sign = -1; } // Handle negative sign case '+': { p++; } break; // Handle positive sign default: break; // No sign or prefix } uint32_t len = strlen(p); // Length of the number string const char *s = &p[len - 1]; // Pointer to the last character of the number string // Process decimal numbers if (type == 0) { while (s >= p) // Traverse the string backwards { char c = *s; if (c >= '0' && c <= '9') { uint32_t num = c - '0'; /** Convert character to number */ /** Process current digit */ intl addend = intl_umul(base, (intl){num}); // Multiply base by the digit result = intl_add(result, addend); // Add to result /** Multiply base by 10 for the next digit */ base = intl_umul(base, (intl){10}); } else { printf("Invalid character in input string: %c\n", *s); // Error handling return (intl){0}; // Return zero for invalid input } s--; // Move to the previous character } if (sign == -1) // Apply sign if negative { result = intl_neg(result); } } else { // Process non-decimal bases (binary, octal, hexadecimal) uint8_t bit = 0; // Bit position within the current u32 part int index = 0; // Current index in the result array while (s >= p && index < INTL_U32_PARTS) { char c = *s; // Adjust character for hex representation if (c >= 'A' && c <= 'F') c -= 7; // A-F to 10-15 else if (c >= 'a' && c <= 'f') c -= 39; // a-f to 10-15 // Validate and process the character if (c >= '0' && c < ('0' + ttable[type])) { result.u32[index] |= ((c - '0') << bit); // Set the value in the corresponding bit bit += btable[type]; // Update the bit position if (bit >= 32) // If bit exceeds 32, move to the next part { bit -= 32; // Reset bit position index++; // Move to the next u32 part } } else { printf("Invalid character in input string: %c\n", *s); // Error handling return (intl){0}; // Return zero for invalid input } s--; // Move to the previous character } } return result; // Return the resulting intl number } /** * \brief Converts a 32-bit unsigned integer to an intl number. * * This function initializes the first 32-bit segment of the intl structure * with the provided 32-bit unsigned integer value, while the other segments * are set to zero. This allows for easy conversion from a standard integer type * to the custom 128-bit representation. * * \param[in] value: The 32-bit unsigned integer to convert. * \return The corresponding intl number initialized with the given value. */ intl intl_from2(int value) { intl result = {0}; memcpy(&result, &value, sizeof(value)); if (value < 0) { memset(((char *)(&result)) + sizeof(value), -1, sizeof(result) - sizeof(value)); } return result; } /** * \brief Determines the sign of an intl number. * * This function checks the sign of the given 128-bit unsigned integer * (intl) based on its representation. It first examines the most significant * bit of the highest 32-bit segment to determine if the number is negative. * If this bit is set, the function returns -1, indicating a negative value. * If all segments are zero, it returns 0, indicating that the number is zero. * If the number is positive, it returns 1. * * \param[in] a: The intl number to evaluate for its sign. * \return -1 if the number is negative, 0 if the number is zero, and * 1 if the number is positive. */ int intl_sign(intl a) { // Check if the sign bit of the highest 32-bit part is set if (a.u32[INTL_U32_PARTS - 1] & 0x80000000) return -1; // Check if the number is zero for (int i = INTL_U32_PARTS - 1; i >= 0; i--) { if (a.u32[i] != 0) return 1; // Return 1 if any part is non-zero } return 0; // Return 0 if all parts are zero } /** * \brief Converts an intl number to a decimal string. * * This function converts a 128-bit integer (intl) into its * decimal string representation. The resulting string is * constructed by repeatedly dividing the number by 10 and * storing the remainders. The function handles both positive * and negative integers, including the special case where the * number is zero. * * \param[in] a: The intl number to convert. * \param[out] buffer: The buffer to store the resulting decimal string. * * \return A pointer to the resulting decimal string. */ const char* intl_sdec(intl a, char buffer[INTL_MAX_DEC]) { intl ten = intl(10); /** Base 10 for conversion */ intl remainder; // To hold the remainder during division intl temp = a; // Temporary variable for manipulation char *p = buffer; // Pointer for writing to the buffer // Check if the number is negative if (a.u32[INTL_U32_PARTS - 1] & 0x80000000) // Check sign bit { temp = intl_neg(a); // Negate the number for conversion } /** Calculate decimal string of intl */ while (intl_ucmp(temp, (intl){0}) > 0) // While the number is positive { remainder = intl_umod(temp, ten); // Get remainder when divided by 10 char digit = '0' + remainder.u32[0]; // Convert remainder to character *p++ = digit; // Store character in buffer temp = intl_udiv(temp, ten, NULL); // Update temp for integer division by 10 } // Handle special case for 0 if (p == buffer) { *p++ = '0'; // If no digits were added, it's zero *p = 0; // Null-terminate the string } else { // If the original number was negative, add '-' sign if (a.u32[INTL_U32_PARTS - 1] & 0x80000000) { *p++ = '-'; // Append negative sign } *p-- = 0; // Null-terminate the string // Reverse the string to correct the order of digits char *s = buffer; // Pointer to the start of the buffer while (s < p) // Swap characters { char t = *s; // Temporary variable for swapping *s = *p; // Swap start and end *p = t; s++; // Move pointers towards the center p--; } } return buffer; // Return the resulting decimal string } /** * \brief Converts an intl number to a hexadecimal string. * * This function converts a 128-bit integer (intl) into a * hexadecimal string representation. The resulting string is * formatted as a sequence of hexadecimal digits, with each * part of the intl number contributing 8 digits to the final * string. The string is stored in the provided buffer. * * \param[in] a: The intl number to convert. * \param[out] buffer: The buffer to store the resulting hexadecimal string. * * \return A pointer to the resulting hexadecimal string. */ const char* intl_shex(intl a, char buffer[INTL_MAX_HEX]) { char temp[9]; /** Temporary buffer for each part (8 hex digits + null terminator) */ char skip = 1; /** Skip invalid 0 */ char *p = buffer; buffer[0] = '\0'; /** Initialize as empty string */ // Convert each part of the intl number to hexadecimal, starting from the least significant part for (int i = INTL_U32_PARTS - 1; i >= 0; i--) { if (skip == 1) { if (a.u32[i] != 0) skip = 0; else continue; /** Prevent leading zero */ } snprintf(temp, sizeof(temp), "%08X", a.u32[i]); /** Convert to hex and store in temp */ strcat(p, temp); /** Append converted hex to the result string */ p += 8; } /** Prevent leading zero */ while (*buffer == '0') buffer++; // Uncomment this line to remove leading zeros /** a == 0, print 0 only */ if (p == buffer) { buffer[0] = '0'; buffer[1] = '\0'; } return buffer; /** Return the resulting hexadecimal string */ } /** * \brief Converts an intl number to a binary string. * * This function converts a given 128-bit unsigned integer (intl) * into a binary string representation. It extracts each bit of the * integer and stores the corresponding '0' or '1' character in the * provided buffer. The resulting string is left-aligned, with leading * zeros trimmed. * * \param[in] a: The intl number to convert. * \param[out] buffer: The buffer to store the resulting binary string. * It should be large enough to hold the binary * representation (at least INTL_MAX_BIN characters). * \return A pointer to the first non-zero character in the binary string, * or a pointer to the buffer if the number is zero. */ const char* intl_sbin(intl a, char buffer[INTL_MAX_BIN]) { int i, j; uint8_t *base = (uint8_t *)&a; // Cast intl to a byte array int width = sizeof(a); // Get the size of intl char *p = buffer; // Pointer to the current position in buffer // Convert each byte to binary for (i = width - 1; i >= 0; i--) { for (j = 7; j >= 0; j--) { *p++ = (((base[i]) >> (j) & 1) ? '1' : '0'); // Extract bits } } *p = 0; // Null-terminate the string // Trim leading zeros and find the first '1' while (buffer < p - 1) { if (*buffer == '1') break; // Stop at the first '1' buffer++; // Skip leading zeros } return buffer; // Return pointer to the trimmed string } /** * \brief Compares two intl unsigned numbers. * * This function compares two 128-bit unsigned integers (intl) * by examining each 32-bit segment from the most significant to * the least significant. It returns 1 if the first number is * greater than the second, -1 if it is less, and 0 if they are * equal. The comparison is done in a way that respects the * unsigned nature of the integers. * * \param[in] a: The first number to compare. * \param[in] b: The second number to compare. * \return 1 if a > b, -1 if a < b, and 0 if a == b. */ static int intl_ucmp(intl a, intl b) { // Compare each 32-bit part from the most significant to the least significant for (int i = INTL_U32_PARTS - 1; i >= 0; i--) { if (a.u32[i] > b.u32[i]) return 1; // a is greater if (a.u32[i] < b.u32[i]) return -1; // a is less } return 0; // a and b are equal } /** * \brief Compares two intl numbers. * * This function compares two 128-bit integers (intl) and * determines their relative order. The comparison is performed * starting from the most significant part (highest order) to * the least significant part (lowest order). * * \param[in] a: The first number to compare. * \param[in] b: The second number to compare. * * \return 1 if a > b, -1 if a < b, 0 if a == b. */ int intl_cmp(intl a, intl b) { // Compare each 32-bit part from the most significant to the least significant for (int i = INTL_U32_PARTS - 1; i >= 0; i--) { // Compare the current parts as signed integers if ((int32_t)a.u32[i] > (int32_t)b.u32[i]) return 1; // a is greater if ((int32_t)a.u32[i] < (int32_t)b.u32[i]) return -1; // a is less } return 0; // a is equal to b } /** * \brief Computes the two's complement (negation) of an intl number. * * This function calculates the negative representation of a given 128-bit * unsigned integer (intl) using two's complement. It first inverts all bits * of the input number and then adds one to the result. This effectively * represents the negative value of the original number in a signed * integer format. * * \param[in] a: The intl number to negate. * \return The negated intl number (two's complement of a). */ intl intl_neg(intl a) { intl result = {0}; // First, bitwise NOT (invert) the input number for (int i = 0; i < INTL_U32_PARTS; i++) { result.u32[i] = ~a.u32[i]; } // Add one to complete the two's complement operation return intl_inc(result); }