proc float_sum $a $b set $dot "." set $zero "0" // ========================================================= // Разбор числа A // ========================================================= set $regexp "^([0-9]+)" set #n regexp ( 1 $a_int $a $regexp ) set #mantissa_pos size ( $a_int ) + 1 set $regexp "([0-9]+)$" set #n regexp ( #mantissa_pos $a_mantissa $a $regexp ) if ( $a_mantissa == "" ) set $a_mantissa "0" end_if // ========================================================= // Разбор числа B // ========================================================= set $regexp "^([0-9]+)" set #n regexp ( 1 $b_int $b $regexp ) set #mantissa_pos size ( $b_int ) + 1 set $regexp "([0-9]+)$" set #n regexp ( #mantissa_pos $b_mantissa $b $regexp ) if ( $b_mantissa == "" ) set $b_mantissa "0" end_if // ========================================================= // Выравнивание дробных частей // ========================================================= set #a_len size ( $a_mantissa ) set #b_len size ( $b_mantissa ) set #precision #a_len if ( #b_len > #precision ) set #precision #b_len end_if // Дополняем дробную часть A справа нулями set #i #a_len while ( #i < #precision ) set $a_mantissa $a_mantissa$zero set #i #i + 1 end_while // Дополняем дробную часть B справа нулями set #i #b_len while ( #i < #precision ) set $b_mantissa $b_mantissa$zero set #i #i + 1 end_while // ========================================================= // Убираем десятичные точки // // 123.421356 -> 123421356 // 61154.32421 -> 61154324210 // ========================================================= set $a_digits $a_int$a_mantissa set $b_digits $b_int$b_mantissa // ========================================================= // Поразрядное сложение справа налево // ========================================================= set #a_pos size ( $a_digits ) set #b_pos size ( $b_digits ) set #carry 0 set $sum_digits "" while ( ( #a_pos > 0 ) or ( #b_pos > 0 ) or ( #carry > 0 ) ) // Если цифры нет, используем ноль set #da 0 set #db 0 // Получаем очередную цифру числа A if ( #a_pos > 0 ) set $char copy($a_digits #a_pos 1 ) set #da $char set #a_pos #a_pos - 1 end_if // Получаем очередную цифру числа B if ( #b_pos > 0 ) set $char copy($b_digits #b_pos 1 ) set #db $char set #b_pos #b_pos - 1 end_if // Максимум: 9 + 9 + 1 = 19 set #digit #da + #db + #carry if ( #digit >= 10 ) set #digit #digit - 10 set #carry 1 else set #carry 0 end_if // Добавляем цифру слева set $char #digit set $sum_digits $char$sum_digits end_while // ========================================================= // Вставляем десятичную точку // ========================================================= if ( #precision == 0 ) set $result $sum_digits else set #sum_len size ( $sum_digits ) set #int_len #sum_len - #precision if ( #int_len > 0 ) set $result_int copy($sum_digits 1 #int_len ) set #frac_pos #int_len + 1 set $result_frac copy($sum_digits #frac_pos #precision ) else // Случай результата меньше единицы set $result_int "0" set $result_frac $sum_digits set #i #int_len while ( #i < 0 ) set $result_frac 0$result_frac set #i #i + 1 end_while end_if set $result $result_int$dot$result_frac end_if end_proc proc float_sub $a $b set $dot "." set $zero "0" // ========================================================= // Разбор числа A // ========================================================= set $regexp "^([0-9]+)" set #n regexp ( 1 $a_int $a $regexp ) set #mantissa_pos size ( $a_int ) + 1 set $regexp "([0-9]+)$" set #n regexp ( #mantissa_pos $a_mantissa $a $regexp ) if ( $a_mantissa == "" ) set $a_mantissa "0" end_if // ========================================================= // Разбор числа B // ========================================================= set $regexp "^([0-9]+)" set #n regexp ( 1 $b_int $b $regexp ) set #mantissa_pos size ( $b_int ) + 1 set $regexp "([0-9]+)$" set #n regexp ( #mantissa_pos $b_mantissa $b $regexp ) if ( $b_mantissa == "" ) set $b_mantissa "0" end_if // ========================================================= // Выравнивание дробных частей // ========================================================= set #a_len size ( $a_mantissa ) set #b_len size ( $b_mantissa ) set #precision #a_len if ( #b_len > #precision ) set #precision #b_len end_if set #i #a_len while ( #i < #precision ) set $a_mantissa $a_mantissa$zero set #i #i + 1 end_while set #i #b_len while ( #i < #precision ) set $b_mantissa $b_mantissa$zero set #i #i + 1 end_while // ========================================================= // Удаляем десятичные точки // ========================================================= set $a_digits $a_int$a_mantissa set $b_digits $b_int$b_mantissa // ========================================================= // Определяем, какое число больше // #sign = 0: A >= B // #sign = 1: A < B // ========================================================= set #a_len size ( $a_digits ) set #b_len size ( $b_digits ) set #sign 0 if ( #a_len < #b_len ) set #sign 1 else if ( #a_len == #b_len ) set #i 1 set #compare 0 while ( #i <= #a_len ) if ( #compare == 0 ) set $char_a copy($a_digits #i 1) set $char_b copy($b_digits #i 1) set #da $char_a set #db $char_b if ( #da > #db ) set #compare 1 end_if if ( #da < #db ) set #compare -1 end_if end_if set #i #i + 1 end_while if ( #compare < 0 ) set #sign 1 end_if end_if end_if // ========================================================= // Выбираем уменьшаемое и вычитаемое // ========================================================= if ( #sign == 0 ) set $big_digits $a_digits set $small_digits $b_digits else set $big_digits $b_digits set $small_digits $a_digits end_if // ========================================================= // Поразрядное вычитание справа налево // ========================================================= set #big_pos size ( $big_digits ) set #small_pos size ( $small_digits ) set #borrow 0 set $result_digits "" while ( #big_pos > 0 ) set #da 0 set #db 0 if ( #big_pos > 0 ) set $char copy($big_digits #big_pos 1) set #da $char set #big_pos #big_pos - 1 end_if if ( #small_pos > 0 ) set $char copy($small_digits #small_pos 1) set #db $char set #small_pos #small_pos - 1 end_if set #digit #da - #borrow - #db if ( #digit < 0 ) set #digit #digit + 10 set #borrow 1 else set #borrow 0 end_if set $char #digit set $result_digits $char$result_digits end_while // ========================================================= // Удаляем ведущие нули // ========================================================= set #sum_len size ( $result_digits ) set #i 1 while ( #i < #sum_len ) set $char copy($result_digits #i 1) if ( $char != "0" ) break else set #i #i + 1 end_if end_while set $result_digits copy($result_digits #i #sum_len) // ========================================================= // Вставляем десятичную точку // ========================================================= if ( #precision == 0 ) set $result $result_digits else set #sum_len size ( $result_digits ) set #int_len #sum_len - #precision if ( #int_len > 0 ) set $result_int copy($result_digits 1 #int_len) set #frac_pos #int_len + 1 set $result_frac copy($result_digits #frac_pos #precision) else set $result_int "0" set $result_frac $result_digits set #i #int_len while ( #i < 0 ) set $result_frac 0$result_frac set #i #i + 1 end_while end_if set $result $result_int$dot$result_frac end_if // ========================================================= // Добавляем знак // ========================================================= if ( #sign == 1 ) if ( $result != "0.0" ) set $result -$result end_if end_if set $float_sub $result end_proc // ========================================================= // Умножение десятичных чисел без использования больших # // #name — числовая переменная int // $name — строковая переменная // // Поддерживаются: // 123.421356 // 61154.32421 // 12 // 0.25 // -12.5 // ========================================================= proc float_mul $a $b set $dot "." set $zero "0" // ========================================================= // Обрабатываем знак A // ========================================================= set #a_negative 0 set $a_first copy($a 1 1) if ( $a_first == "-" ) set #a_negative 1 set #a_size size ( $a ) set $a copy($a 2 #a_size) end_if // ========================================================= // Обрабатываем знак B // ========================================================= set #b_negative 0 set $b_first copy($b 1 1) if ( $b_first == "-" ) set #b_negative 1 set #b_size size ( $b ) set $b copy($b 2 #b_size) end_if // ========================================================= // Разбор числа A // ========================================================= set $regexp "^([0-9]+)" set #n regexp ( #pos $a_int $a $regexp ) set $regexp "([0-9]+)$" set #n regexp ( #pos $a_mantissa $a $regexp ) if ( $a_mantissa == "" ) set $a_mantissa "" end_if // ========================================================= // Разбор числа B // ========================================================= set $regexp "^([0-9]+)" set #n regexp ( #pos $b_int $b $regexp ) set $regexp "([0-9]+)$" set #n regexp ( #pos $b_mantissa $b $regexp ) if ( $b_mantissa == "" ) set $b_mantissa "" end_if // ========================================================= // Количество знаков после точки // При умножении точности складываются // ========================================================= set #a_fraction_len size ( $a_mantissa ) set #b_fraction_len size ( $b_mantissa ) set #precision #a_fraction_len + #b_fraction_len // ========================================================= // Убираем десятичные точки // Нули справа НЕ добавляем // ========================================================= set $a_digits $a_int$a_mantissa set $b_digits $b_int$b_mantissa // ========================================================= // Удаляем ведущие нули из A // ========================================================= set #a_digits_len size ( $a_digits ) set #i 1 while ( #i < #a_digits_len ) set $char copy($a_digits #i 1) if ( $char != "0" ) break end_if set #i #i + 1 end_while set $a_digits copy($a_digits #i #a_digits_len) // ========================================================= // Удаляем ведущие нули из B // ========================================================= set #b_digits_len size ( $b_digits ) set #i 1 while ( #i < #b_digits_len ) set $char copy($b_digits #i 1) if ( $char != "0" ) break end_if set #i #i + 1 end_while set $b_digits copy($b_digits #i #b_digits_len) // ========================================================= // Умножение строковых чисел // ========================================================= set #a_digits_len size ( $a_digits ) set #b_digits_len size ( $b_digits ) set $result_digits "0" set #b_pos #b_digits_len while ( #b_pos > 0 ) set $char copy($b_digits #b_pos 1) set #multiplier $char set #a_pos #a_digits_len set #carry 0 set $partial "" // ========================================================= // Умножаем A на одну цифру B // ========================================================= while ( #a_pos > 0 ) set $char copy($a_digits #a_pos 1) set #da $char set #total #da * #multiplier + #carry set #carry 0 // Остаток от деления на 10 // без использования больших чисел while ( #total >= 10 ) set #total #total - 10 set #carry #carry + 1 end_while set $char #total set $partial $char$partial set #a_pos #a_pos - 1 end_while // ========================================================= // Добавляем перенос // ========================================================= if ( #carry > 0 ) set $char #carry set $partial $char$partial end_if // ========================================================= // Добавляем разрядный сдвиг // ========================================================= set #shift #b_digits_len - #b_pos set #i 0 while ( #i < #shift ) set $partial $partial$zero set #i #i + 1 end_while // ========================================================= // Складываем result_digits и partial // ========================================================= set #result_pos size ( $result_digits ) set #partial_pos size ( $partial ) set #carry 0 set $sum_digits "" while ( ( #result_pos > 0 ) or ( #partial_pos > 0 ) or ( #carry > 0 ) ) set #da 0 set #db 0 if ( #result_pos > 0 ) set $char copy($result_digits #result_pos 1) set #da $char set #result_pos #result_pos - 1 end_if if ( #partial_pos > 0 ) set $char copy($partial #partial_pos 1) set #db $char set #partial_pos #partial_pos - 1 end_if set #digit #da + #db + #carry if ( #digit >= 10 ) set #digit #digit - 10 set #carry 1 else set #carry 0 end_if set $char #digit set $sum_digits $char$sum_digits end_while set $result_digits $sum_digits set #b_pos #b_pos - 1 end_while // ========================================================= // Удаляем ведущие нули результата // ========================================================= set #result_len size ( $result_digits ) set #i 1 while ( #i < #result_len ) set $char copy($result_digits #i 1) if ( $char != "0" ) break end_if set #i #i + 1 end_while set $result_digits copy($result_digits #i #result_len) // ========================================================= // Вставляем десятичную точку // ========================================================= if ( #precision == 0 ) set $result $result_digits else set #result_len size ( $result_digits ) set #int_len #result_len - #precision if ( #int_len > 0 ) set $result_int copy($result_digits 1 #int_len) set #frac_pos #int_len + 1 set $result_frac copy($result_digits #frac_pos #precision) else set $result_int "0" set $result_frac $result_digits set #i #int_len while ( #i < 0 ) set $result_frac 0$result_frac set #i #i + 1 end_while end_if set $result $result_int$dot$result_frac end_if // ========================================================= // Проверяем нулевой результат // ========================================================= set #result_is_zero 1 set #result_len size ( $result_digits ) set #i 1 while ( #i <= #result_len ) set $char copy($result_digits #i 1) if ( $char != "0" ) set #result_is_zero 0 break end_if set #i #i + 1 end_while // ========================================================= // Добавляем знак // ========================================================= if ( #result_is_zero == 0 ) if ( #a_negative != #b_negative ) set $result -$result end_if end_if set $float_mul $result end_proc // ========================================================= // Деление десятичных чисел // // Третий параметр #precision — количество знаков // после десятичной точки. // // Пример: // call float_div $a $b 8 // log $float_div // // Деление выполняется с усечением результата, // без округления. // ========================================================= proc float_div $a $b #precision set $dot "." set $zero "0" // ========================================================= // Обрабатываем знак A // ========================================================= set #a_negative 0 set $first_char copy($a 1 1) if ( $first_char == "-" ) set #a_negative 1 set #a_size size ( $a ) set $a copy($a 2 #a_size) end_if // ========================================================= // Обрабатываем знак B // ========================================================= set #b_negative 0 set $first_char copy($b 1 1) if ( $first_char == "-" ) set #b_negative 1 set #b_size size ( $b ) set $b copy($b 2 #b_size) end_if // ========================================================= // Разбор числа A // ========================================================= set $a_int "" set $a_mantissa "" set $regexp "^([0-9]+)" set #n regexp ( 1 $a_int $a $regexp ) set #mantissa_pos size ( $a_int ) + 1 set $regexp "([0-9]+)$" set #n regexp ( #mantissa_pos $a_mantissa $a $regexp ) if ( $a_mantissa == "" ) set $a_mantissa "" end_if // ========================================================= // Разбор числа B // ========================================================= set $b_int "" set $b_mantissa "" set $regexp "^([0-9]+)" set #n regexp ( 1 $b_int $b $regexp ) set #mantissa_pos size ( $b_int ) + 1 set $regexp "([0-9]+)$" set #n regexp ( #mantissa_pos $b_mantissa $b $regexp ) if ( $b_mantissa == "" ) set $b_mantissa "" end_if // ========================================================= // Убираем десятичные точки // ========================================================= set $a_digits $a_int$a_mantissa set $b_digits $b_int$b_mantissa set #a_fraction_len size ( $a_mantissa ) set #b_fraction_len size ( $b_mantissa ) // ========================================================= // Удаляем ведущие нули из A // ========================================================= set #a_digits_len size ( $a_digits ) set #i 1 while ( #i < #a_digits_len ) set $char copy($a_digits #i 1) if ( $char != "0" ) break end_if set #i #i + 1 end_while set $a_digits copy($a_digits #i #a_digits_len) // ========================================================= // Удаляем ведущие нули из B // ========================================================= set #b_digits_len size ( $b_digits ) set #i 1 while ( #i < #b_digits_len ) set $char copy($b_digits #i 1) if ( $char != "0" ) break end_if set #i #i + 1 end_while set $b_digits copy($b_digits #i #b_digits_len) // ========================================================= // Проверка деления на ноль // ========================================================= set #division_by_zero 0 if ( $b_digits == "0" ) set #division_by_zero 1 else // ========================================================= // Масштабирование чисел // // shift = precision + знаки B - знаки A // ========================================================= set #shift #precision + #b_fraction_len - #a_fraction_len if ( #shift >= 0 ) set #i 0 while ( #i < #shift ) set $a_digits $a_digits$zero set #i #i + 1 end_while else set #shift_abs 0 - #shift set #i 0 while ( #i < #shift_abs ) set $b_digits $b_digits$zero set #i #i + 1 end_while end_if // ========================================================= // Длинное целочисленное деление // ========================================================= set $quotient "" set $remainder "" set #a_digits_len size ( $a_digits ) set #a_pos 1 while ( #a_pos <= #a_digits_len ) set $char copy($a_digits #a_pos 1) set $remainder $remainder$char // ========================================================= // Удаляем ведущие нули из остатка // ========================================================= set #remainder_len size ( $remainder ) set #i 1 while ( #i < #remainder_len ) set $char_rem copy($remainder #i 1) if ( $char_rem != "0" ) break end_if set #i #i + 1 end_while set $remainder copy($remainder #i #remainder_len) // ========================================================= // Ищем очередную цифру частного // ========================================================= set #quotient_digit 0 set #compare 0 while ( #quotient_digit < 10 ) set #remainder_len size ( $remainder ) set #divisor_len size ( $b_digits ) set #compare 0 if ( #remainder_len > #divisor_len ) set #compare 1 else if ( #remainder_len < #divisor_len ) set #compare -1 else set #i 1 set #compare 0 while ( #i <= #remainder_len ) if ( #compare == 0 ) set $char_rem copy($remainder #i 1) set $char_div copy($b_digits #i 1) set #dr $char_rem set #dd $char_div if ( #dr > #dd ) set #compare 1 end_if if ( #dr < #dd ) set #compare -1 end_if end_if set #i #i + 1 end_while end_if end_if if ( #compare < 0 ) break end_if // ========================================================= // remainder = remainder - b_digits // ========================================================= set #rem_pos size ( $remainder ) set #div_pos size ( $b_digits ) set #borrow 0 set $subtracted "" while ( #rem_pos > 0 ) set #dr 0 set #dd 0 set $char copy($remainder #rem_pos 1) set #dr $char set #rem_pos #rem_pos - 1 if ( #div_pos > 0 ) set $char copy($b_digits #div_pos 1) set #dd $char set #div_pos #div_pos - 1 end_if set #digit #dr - #borrow - #dd if ( #digit < 0 ) set #digit #digit + 10 set #borrow 1 else set #borrow 0 end_if set $char #digit set $subtracted $char$subtracted end_while // ========================================================= // Удаляем ведущие нули из нового остатка // ========================================================= set #subtracted_len size ( $subtracted ) set #i 1 while ( #i < #subtracted_len ) set $char copy($subtracted #i 1) if ( $char != "0" ) break end_if set #i #i + 1 end_while set $remainder copy($subtracted #i #subtracted_len) set #quotient_digit #quotient_digit + 1 end_while // ========================================================= // Добавляем цифру частного // ========================================================= set $char #quotient_digit set $quotient $quotient$char set #a_pos #a_pos + 1 end_while // ========================================================= // Удаляем ведущие нули из частного // ========================================================= set #quotient_len size ( $quotient ) set #i 1 while ( #i < #quotient_len ) set $char copy($quotient #i 1) if ( $char != "0" ) break end_if set #i #i + 1 end_while set $quotient copy($quotient #i #quotient_len) // ========================================================= // Вставляем десятичную точку // ========================================================= if ( #precision == 0 ) set $result $quotient else set #quotient_len size ( $quotient ) set #required_len #precision + 1 while ( #quotient_len < #required_len ) set $quotient 0$quotient set #quotient_len #quotient_len + 1 end_while set #int_len #quotient_len - #precision set $result_int copy($quotient 1 #int_len) set #frac_pos #int_len + 1 set $result_frac copy($quotient #frac_pos #precision) set $result $result_int$dot$result_frac end_if // ========================================================= // Проверяем нулевой результат // ========================================================= set #result_is_zero 1 set #result_len size ( $quotient ) set #i 1 while ( #i <= #result_len ) set $char copy($quotient #i 1) if ( $char != "0" ) set #result_is_zero 0 break end_if set #i #i + 1 end_while // ========================================================= // Добавляем знак // ========================================================= if ( #result_is_zero == 0 ) if ( #a_negative != #b_negative ) set $result -$result end_if end_if end_if // ========================================================= // Возвращаем результат // ========================================================= if ( #division_by_zero == 1 ) set $float_div "division_by_zero" else set $float_div $result end_if end_proc end_script