Как привести вещественные числа к одному порядку при простых арифметических операциях UNIX C
Создали следующую структуру для хранения больших чисел:
typedef enum {
L_BITS, //младшие биты
M_BITS, //средние
H_BITS, //старшие
S_BITS, //16-23 бит под экспаненту 31 под знак
ALL_BITS
} e_dec_bit_t;
typedef struct {
int bits[ALL_BITS];
} my_decimal;
#define INT_BITS sizeof(int) * 8
#define DEC_BITS ALL_BITS * sizeof(int) * 8
#define NEW_DECIMAL(l_b, m_b, h_b, scale, sign) \
{ l_b, m_b, h_b, ((scale << 16) | (sign << 31)) }
S_BITS
- Биты от 0 до 15, младшее слово, не используются и должны быть равны нулю;
- Биты с 16 по 23 должны содержать показатель степени от 0 до 28, который указывает степень 10 для разделения целого числа;
- Биты с 24 по 30 не используются и должны быть равны нулю;
- Бит 31 содержит знак;
Decimal число - это значение с плавающей точкой, состоящее из знака, числового значения, где каждая цифра находится в диапазоне от 0 до 9, и коэффициента масштабирования, который указывает положение десятичной точки, разделяющей целые и дробные части числового значения.
Двоичное представление Decimal состоит из 1-разрядного знака, 96-разрядного целого числа и коэффициента масштабирования, используемого для деления 96-разрядного целого числа и указания того, какая его часть является десятичной дробью. Коэффициент масштабирования неявно равен числу 10, возведенному в степень в диапазоне от 0 до 28. Следовательно, двоичное представление Decimal имеет вид ((от -2^96 до 2^96) / 10^(от 0 до 28)), где -(2^96-1) равно минимальному значению, а 2^96-1 равно максимальному значению.
К примеру имеем следующие вводные данные:
M1 = 123456 exp1 = 2 -> 12.3456
M2 = 123456 exp2 = 3 -> 123.456
Здесь я возможно ошибаюсь и следует думать иначе:
M1 = 123456 exp1 = 2 -> 1234.56
M2 = 123456 exp2 = 3 -> 123.456
В данном случае как мне легче считать, так это в 10 форме (так мне легче представлять), я sub exp2 - exp1 = 1
И пока в цикле я ниже этого значения а именно 1 я представляю что у первого числа мнимый 0 в начале и выполняю действия как:
012345(6) +
123456 =
135801
Числа которые я складываю выглядят следующим образом если не учитывать порядок:
1 | 1110 0010 0100 0000 +
1 | 1110 0010 0100 0000 =
10 | 0001 0010 0111 1001
В каждом из первых трёх чанков выполняем все опперации побитово:
bool get_bit(const my_decimal *src, const size_t index) {
int mask = (1LU << (index % 0x20));
return src->bits[index / 0x20] & mask;
}
*Вопрос в следующем: как выполнять все операции побитово, учитывая порядок находящийся в между 16-23 bits?
Все действия должны быть подобны Decimal in C*
Я вероятно думаю в 10 формате, и не замечаю явных вещей.
Ответы (1 шт):
Для сложения и вычитания в своей реализации пришлось привести числа к единому порядку, а именно к большему. Если дробная часть уж слешком велика и сложение происходит также с большей целой частью я жертвую самым последним разрядом(потеря в точности).
int normalize_numbers(my_decimal *a, my_decimal *b) {
int flag = my_NORMAL_VALUE;
int scale = get_scale(a) - get_scale(b);
my_decimal temp_d = create_integer_decimal(10, 0, 0);
if (scale < 0) {
flag = multiple_in_loop(a, temp_d, abs(scale));
} else if (scale > 0) {
flag = multiple_in_loop(b, temp_d, abs(scale));
}
return flag;
}
int multiple_in_loop(my_decimal *src, my_decimal multiplicand, size_t times) {
int flag = my_NORMAL_VALUE;
for (size_t i = 0; i < times && flag == my_NORMAL_VALUE; ++i) {
s21_decimal t_src = *src;
memset(src, 0, sizeof(s21_decimal));
flag = my_mul(t_src, multiplicand, src);
}
return flag;
}
А таким образом жертвую
int reduction_order(my_decimal *value_1, my_decimal *value_2) {
int flag = my_NORMAL_VALUE;
int s_v1 = get_scale(value_1);
int s_v2 = get_scale(value_1);
s21_decimal denominator = create_integer_decimal(10, 0, 0);
s21_decimal t_value_1 = create_integer_decimal(0, 0, 0);
s21_decimal t_value_2 = create_integer_decimal(0, 0, 0);
if (s_v1 && s_v1 > s_v2) {
flag = my_div(*value_1, denominator, &t_value_1);
*value_1 = t_value_1;
} else if (s_v2 && s_v1 < s_v2) {
flag = my_div(*value_2, denominator, &t_value_2);
*value_2 = t_value_2;
} else if (s_v1 == s_v2) {
flag = my_div(*value_1, denominator, &t_value_1);
flag = my_div(*value_2, denominator, &t_value_2);
*value_1 = t_value_1;
*value_2 = t_value_2;
}
return flag;
}