A PHP libarary to support modular arithmetic, aka clock arithmetic.
This software is made to overcome the limit of modulo operation in PHP where a negative modulus (divisor) would be treated as a positive one.
It also provide convenient modular arithmetic operations.
It is based on arbitrary precision calculations made with BC Math Extended, check its API documentation to more info about the Number class.
- Requirement
- Usage
- Operations on a
ModularNumber - Operations on a
ModularRelativeNumber - API documentation
- PHP ^8.4
- BCMath extension
composer install marcoconsiglio/modular-arithmeticA ModularNumber is a number placed in a ring with positive numbers starting from zero.
The length of this ring is the modulus.
A ModularRelativeNumber is a number placed in a Ring whose start and end can be relative (like -180/180). In this case the start coincides with the end.
Construct a ModularNumber with its modulus if the ring has only positive numbers.
use Marcoconsiglio\ModularArithmetic\ModularNumber;
$hour_on_a_clock = 12;
$current_hour = new ModularNumber(15, $hour_on_a_clock);
echo "The current hour is $current_hour->value o'clock.";The current hour is 3 o'clock.
Construct a ModularNumber with its Ring (or start and end of the Ring)
use Marcoconsiglio\ModularArithmetic\ModularRelativeNumber;
use Marcoconsiglio\ModularArithmetic\Ring;
$start = -180;
$end = 180;
$steering_wheel = ModularRelativeNumber::createFromExtremes(
30, -180, 180
);
echo "Turn left {$steering_wheel->value}°" . PHP_EOL;
$steering_wheel = ModularRelativeNumber::createFromRing(
-45, new Ring($start, $end)
);
echo "Now turn right {$steering_wheel->value}°" . PHP_EOL;Turn left 30°
Now turn right -45°
You can add two ModularNumber: the sum will be a ModularNumber instance.
use Marcoconsiglio\ModularArithmetic\ModularNumber;
$hour_on_a_clock = 12;
$work_start = new ModularNumber(9, $hour_on_a_clock);
$working_time = new ModularNumber(9, $hour_on_a_clock);
$work_end = $work_start->add($working_time->value);
echo "I'm going to start to work at {$work_start->value} o'clock a.m.\n";
echo "I'll work for {$working_time->value} hours.\n";
echo "I'll finish to work at {$work_end->value} o'clock p.m.";I'm going to start to work at 9 o'clock a.m.
I'll work for 9 hours.
I'll finish to work at 6 o'clock p.m.
You can multiply two ModularNumber: the product will be a ModularNumber instance.
use Marcoconsiglio\ModularArithmetic\ModularNumber;
$hours_in_a_day = 24;
$start_shift = new ModularNumber(0, $hours_in_a_day); /* midnight */
$shift_duration = new ModularNumber(3, $hours_in_a_day);
$my_shift = new ModularNumber(5, $hours_in_a_day); /* 5th turn */
$time_to_wait = $shift_duration->multiply($my_shift);
$my_shift_start = $start_shift->add($time_to_wait);
echo "There is a new guard shift every {$shift_duration->value} hours.\n";
echo "My shift, starts at {$my_shift_start->value} o'clock.";There is a new guard shift every 3 hours.
My shift, the 5th, starts at 15 o'clock.
You can raise to power ModularNumber: the result will be a ModularNumber instance.
use Marcoconsiglio\ModularArithmetic\ModularNumber;
$alphabet_lenght = 26;
$alphabet_set = range('A', 'Z');
$message = ['H', 'E', 'L', 'L', 'O'];
$encrypted_message = [];
$cypher_key = 3;
echo "Encrypting the message:\n";
echo implode("", $message)."\n";
foreach ($message as $char) {
$unencrypted_index = new ModularNumber(
array_search($char, $alphabet_set),
$alphabet_lenght
);
$encrypted_index = $unencrypted_index->power($cypher_key);
$encrypted_message[] = $alphabet_set[$encrypted_index->value];
}
echo "Encrypted message:\n";
echo implode("", array: $encrypted_message);Encrypting the message:
HELLO
Encrypted message:
FMFFO
Only addition is available for ModularRelativeNumbers. To perform subtraction, add a negative Number.
use MarcoConsiglio\ModularArithmetic\ModularNumber;
use MarcoConsiglio\ModularArithmetic\ModularRelativeNumber;
use MarcoConsiglio\ModularArithmetic\Ring;
$ring = new Ring(-180, 180);
$moon_longitude = new ModularNumber(60, $ring->length);
$sun_longitude = new ModularNumber(330, $ring->length);
$angular_distance = ModularRelativeNumber::createFromRing(0, $ring);
$angular_distance = $angular_distance->add($sun_longitude->value);
$angular_distance = $angular_distance->add($moon_longitude->value->opposite());
$test = "The sun is at {$sun_longitude->value}°." . PHP_EOL;
$test .= "The moon is at {$moon_longitude->value}°." . PHP_EOL;
$test .= "The angular distance between the two is {$angular_distance->value}°." . PHP_EOL;The sun is at 330°.
The moon is at 60°.
The angular distance between the two is -90°.
$ring = new Ring(-180, 180);
echo "The ring of numbers is a range from {$ring->start} to {$ring->end}." . PHP_EOL;
$a = ModularRelativeNumber::createFromRing(90, $ring);
$b = new Number(180);
$c = new Number(270);
echo "{$a->value} + {$b->value} = {$a->plus($b)->value}" . PHP_EOL;
echo "{$a->value} + {$c->value} = {$a->plus($c)->value}" . PHP_EOL;The ring of numbers is a range from -180 to 180.
90 + 180 = -90
90 + 270 = 0
See more on the API documentation at ./docs/html/index.html.