package ONO::Lib::Math;
################################################################################
# COPYRIGHT / LICENSE #
################################################################################
#
# This file is part of the ONO Software Project.
#
# Copyright (C) 2000-2025 Jos KIRPS [ www.kirps.com | jos_AT_kirps_DOT_com ]
# and The Joopita Project [ www.joopita.org | contact_AT_joopita_DOT_com ]
#
# This file, as well as other parts of the ONO Software Project or related
# elements, are FREE SOFTWARE available under the ARTISTIC LICENSE 2.0.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# For the full license, see /ono/osr/license/LICENSE.txt, or write to
# jos_AT_kirps_DOT_com or contact_AT_joopita_DOT_com.
#
################################################################################
# END OF COPYRIGHT / LICENSE, HERE COMES THE CODE ... #
################################################################################
use CGI;
use strict;
use ONO::Lib::Math::HTML;
use ONO::Lib::Data::Numbers::Primes;
#: This library contains everything related to mathematics.
sub calc {
#: Basic operations with two numbers.
#: See also calc_string(), calc_first(), calc_second().
my (
$self,
$num1,
$num2,
$op,
) = @_;
my $res = 0;
if ($op eq "add" || $op eq "+") {
$res = $num1 + $num2;
}
if ($op eq "sub" || $op eq "-") {
$res = $num1 - $num2;
}
if ($op eq "mul" || $op eq "*" || $op eq "x") {
$res = $num1 * $num2;
}
if (($op eq "div" || $op eq ":" || $op eq "/") && $num2) {
$res = $num1 / $num2;
}
return $res;
}
sub calc_string {
#: Similar to calc(), but allows to execute a string including more
#: complex calculations, like ( 3 x 3) + ( 10 / 2 ) = ... for example.
my $string = lc $_[1];
$string =~ s~add~\+~g;
$string =~ s~sub~\-~g;
$string =~ s~(mul|x)~\*~g;
$string =~ s~(div|:)~\/~g;
$string =~ s~[^0-9\ \+\-\*\/\(\)]~~g;
if ($string =~ /[0-9]/) {
return eval($string);
} else {
return "";
}
}
sub calc_first {
my (
$self,
$num1,
$num2,
$op,
) = @_;
#: Like calc(), but return the first element ( ? + a = b ).
my $res = 0;
if ($op eq "add" || $op eq "+") {
$res = $num2 - $num1;
}
if ($op eq "sub" || $op eq "-") {
$res = $num2 + $num1;
}
if (($op eq "mul" || $op eq "*" || $op eq "x") && $num1) {
$res = $num2 / $num1;
}
if ($op eq "div" || $op eq ":" || $op eq "/") {
$res = $num1 * $num2;
}
return $res;
}
sub calc_second {
my (
$self,
$num1,
$num2,
$op,
) = @_;
#: Like calc(), but return the second element ( a + ? = c ).
my $res = 0;
if ($op eq "add" || $op eq "+") {
$res = $num2 - $num1;
}
if ($op eq "sub" || $op eq "-") {
$res = $num1 - $num2;
}
if (($op eq "mul" || $op eq "*" || $op eq "x") && $num1) {
$res = $num2 / $num1;
}
if (($op eq "div" || $op eq ":" || $op eq "/") && $num2) {
$res = $num1 / $num2;
}
return $res;
}
sub comp {
my (
$self,
$num1,
$num2,
) = @_;
#: Compare two numbers, returns, eq, lt, or gt.
my $res;
if ($num1 == $num2) {
$res = "eq";
}
if ($num1 < $num2) {
$res = "lt";
}
if ($num1 > $num2) {
$res = "gt";
}
return $res;
}
sub fraction_reducer {
#: Reduce a fraction.
my (
$self,
$a,
$b,
$optimize_negatives,
) = @_;
my $abs_a = abs($a);
my $abs_b = abs($b);
if ($abs_a > 0 && $abs_a == $abs_b) {
if ($a > 0 && $b > 0 || $a < 0 && $b < 0) {
($a,$b) = (1,1);
}
if ($a > 0 && $b < 0) {
($a,$b) = (1,-1);
}
if ($a < 0 && $b > 0) {
($a,$b) = (-1,1);
}
} else {
if ($a == 0) {
($a,$b) = (0,1);
} else {
foreach my $prime (ONO::Lib::Data::Numbers::Primes->get()) {
if ($prime < $abs_a+1 && $prime < $abs_b+1 && $abs_a > 1 && $abs_b > 1) {
my $whilecounter;
while ($whilecounter < 256 && $a%$prime == 0 && $b%$prime == 0) {
$whilecounter++;
$a = $a/$prime;
$b = $b/$prime;
}
}
}
}
}
if ($optimize_negatives) {
if ($a < 0 && $b < 0) {
$a = abs($a);
$b = abs($b);
} else {
if ($b < 0) {
$a = -$a;
$b = -$b;
}
}
}
return ($a,$b);
}
sub op_to_symbol {
#: Operation (add, sub, mul, div) to symbol.
#:
#: -C colorize (with -H only)
#: -H html mode (universal mode is optimized for PDF)
my $SYM = $_[1];
if ($_[2] =~ /H/) {
if ($_[2] =~ /C/) {
$SYM =~ s~add~<span class="lightgreen">+</span>~;
$SYM =~ s~sub~<span class="lightred">—</span>~;
$SYM =~ s~mul~<span class="lightgreen">•</span>~;
$SYM =~ s~div~<span class="lightred">:</span>~;
$SYM =~ s~eq~=~;
$SYM =~ s~lt~<span class="lightblue"><</span>~;
$SYM =~ s~gt~<span class="lightblue">></span>~;
} else {
$SYM =~ s~add~+~;
$SYM =~ s~sub~—~;
$SYM =~ s~mul~•~;
$SYM =~ s~div~:~;
$SYM =~ s~eq~=~;
$SYM =~ s~lt~<~;
$SYM =~ s~gt~>~;
}
} else {
$SYM =~ s~add~+~;
$SYM =~ s~sub~-~;
$SYM =~ s~mul~x~;
$SYM =~ s~div~:~;
$SYM =~ s~eq~=~;
$SYM =~ s~lt~\>~;
$SYM =~ s~gt~\<~;
}
return $SYM;
}
###############################################################################
# end of script
###############################################################################
1;
__END__