PHP-Math-Integer について
高校数学Aで取り扱う整数論関連ツールをPHPで作ってみました。
Githubで公開しています。Composerでインストールできます。
素数判定、素数生成、素因数分解、最大公約数、最小公倍数、ユークリッドの互除法、不定方程式(ベズーの等式)、分数の約分などを取り扱うことができます。
ただし、対象は自然数のみです。
環境要件
- PHP 8.0.0 (CLI) 以降
- Composer
インストール
作業用ディレクトリを作り、そこでコマンドを実行します。
composer require macocci7/php-math-integer
![](https://macocci7.net/blog/wp-content/uploads/2023/11/php-math-integer-install.png)
クラス一覧
- src/Number.php: 数に関する基本機能
- src/Prime.php: 素数に関する基本機能
- src/Divisor.php: 約数に関する基本機能
- src/Multiple.php: 倍数に関する基本機能
- src/Euclid.php: ユークリッドの互除法に関する基本機能
- src/Bezout.php: ベズーの等式に関する基本機能
- src/Fraction.php: 分数に関する基本機能(おまけ)
基本的な使い方
パッケージに同梱されている example をコピーしていじってみましょう。
cp -ra vendor/macocci7/php-math-integer/example/ ./
各使用例について説明していきます。
Number.php の使用例
example/UseNumber.php を見てみましょう。
<?php
/**
* Examples of operation with
* Macocci7\PhpMathInteger\Number
*/
require_once('../vendor/autoload.php');
use Macocci7\PhpMathInteger\Number;
$n = new Number();
var_dump(
$n->isInt(1), // true
$n->isIntAll([ 1, 2, 3, ]), // true
$n->isNatural(1), // true
$n->isNaturalAll([ 1, 2, 3, ]), // true
$n->isFloat(1.2), // true
$n->isFloatAll([ -2.1, 0.0, 1.2, ]), // true
$n->isNumber(1.2), // true
$n->isNumberAll([ -2, 0.1, 3, ]), // true
$n->isFraction(0.1), // true
$n->isFractionAll([ -0.99, 0.1, 0.99]), // true
$n->sign(-2.5), // -1
$n->int(3.14), // 3
$n->fraction(3.14), // 0.1400...
$n->nthDigit(-3, 123.456), // 6
$n->numberOfDigits(-123.4567), // 3
$n->numberOfFractionalDigits(-12.3456), // 4
);
数に関する基本機能を揃えています。
実行してみましょう。
php -f UseNumber.php > UseNumber.txt
example/UseNumber.txt というテキストファイルに実行結果が保存されています。
開いて中を見てみましょう。
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
int(-1)
int(3)
float(0.14000000000000012)
int(6)
int(3)
int(4)
大体はメソッド名で内容の判別ができると思います。
最後の3つのメソッドだけ説明をしておきます。
$n->nthDigit(-3, 123.456), // 6
第2引数の数値の、第1引数桁目の数値を返します。
桁数の数え方は、第二引数の少数点を起点に左へ正、右へ負となります。
この例の場合は、少数点から右へ3桁目なので6となります。
$n->numberOfDigits(-123.4567), // 3
このメソッドは引数の数値の絶対値の整数部の桁数を返します。
この場合は、整数部は123なので桁数は3となります。
$n->numberOfFractionalDigits(-12.3456), // 4
このメソッドは引数の数値の小数部の桁数を返します。
この場合は、小数部は.3456なので桁数は4となります。
Prime.php の使用例
example/UsePrime.php を開いて見てみましょう。
素数関連の基本機能の使用例です。
<?php
/**
* Examples of operation with
* Macocci7\PhpMathInteger\Prime
*/
require_once('../vendor/autoload.php');
use Macocci7\PhpMathInteger\Prime;
$p = new Prime();
// judge if $n is prime or not
$n = 3;
echo sprintf("Is %d prime? - %s.\n", $n, $p->isPrime($n) ? 'Yes' : 'No');
// judge if all of $n are prime or not
$n = [ 2, 3, 5, ];
echo sprintf(
"Are all of [%s] prime? - %s.\n",
implode(', ', $n),
$p->isPrimeAll($n) ? 'Yes' : 'No'
);
// a prime next to $n
$n = 5;
echo sprintf("A prime next to %d is %d.\n", $n, $p->next($n));
// primes between $a and $b
$a = 6;
$b = 14;
echo sprintf(
"Primes between %d and %d are [%s].\n",
$a,
$b,
implode(', ', $p->between($a, $b))
);
// factorize
$n = 1234567890;
echo sprintf("Factorize %d:\n", $n);
$r = $p->factorize($n);
$l1 = $p->numberOfDigits(max(array_column($r, 0)));
$l2 = $p->numberOfDigits(max(array_column($r, 1)));
$s = str_repeat(' ', $l1 + 1);
$b = $s . str_repeat('-', $l2);
foreach ($r as $f) {
echo (
$f[0]
? sprintf("%" . $l1 . "d)%" . $l2 . "d\n%s\n", $f[0], $f[1], $b)
: sprintf("%s%" . $l2 . "d\n", $s, $f[1])
);
}
// Factorized formula
echo $n . " = " . $p->factorizedFormula($n)['formula'] . "\n";
実行してみましょう。
php -f UsePrime.php > UsePrime.txt
example/UsePrime.txt というファイルができています。
中を見てみましょう。
Is 3 prime? - Yes.
Are all of [2, 3, 5] prime? - Yes.
A prime next to 5 is 7.
Primes between 6 and 14 are [7, 11, 13].
Factorize 1234567890:
2)1234567890
----------
3) 617283945
----------
3) 205761315
----------
5) 68587105
----------
3607) 13717421
----------
3803
1234567890 = 2 * 3 ^ 2 * 5 * 3607 * 3803
見れば大体内容がわかると思います。
掻い摘んで説明していきます。
$p->between($a, $b)
このメソッドは、第一引数と第二引数の間の素数を、小さい順に配列で返します。
$p->factorize($n)
このメソッドは、引数を素因数分解して、その結果を配列で返します。
例えば、30を素因数分解すると次のような配列が返ります。
array(3) {
[0]=>
array(2) {
[0]=>
int(2)
[1]=>
int(30)
}
[1]=>
array(2) {
[0]=>
int(3)
[1]=>
int(15)
}
[2]=>
array(2) {
[0]=>
NULL
[1]=>
int(5)
}
}
この配列は、30を素因数分解した次の結果に対応しています。
2)30
--
3)15
--
5
出力時に桁が揃うように調整しています。
$p->factorizedFormula($n)['formula']
このメソッドは、引数を素因数の積で表した式を返します。
戻り値が色々とてんこ盛りの配列なので、その中から[‘formula’]のみを取り出しています。
Divisor.php の使用例
example/UseDivisor.php を見てみましょう。
約数関連の基本機能の使用例です。
<?php
/**
* Examples of operation with
* Macocci7\PhpMathInteger\Euclid
*/
require_once('../vendor/autoload.php');
use Macocci7\PhpMathInteger\Divisor;
$d = new Divisor();
$a = 12;
$b = 18;
// Number of divisors
echo sprintf("%d has %d divisors.\n", $a, $d->count($a));
// List of all divisors
echo sprintf("[%s]\n", implode(', ', $d->list($a)));
// Common factors
echo sprintf("%d = %s\n", $a, $d->formula($a));
echo sprintf("%d = %s\n", $b, $d->formula($b));
echo sprintf(
"common factors : %s\n",
$d->formula($d->value($d->commonFactors($a, $b)))
);
echo sprintf(
"common divisors : [%s]\n",
implode(', ', $d->commonDivisors($a, $b))
);
// greatest common factor (divisor)
echo sprintf(
"greatest common factor (divisor) : %s\n",
$d->greatestCommonFactor($a, $b)
);
// Reducing fraction
$r = $d->reduceFraction($a, $b);
$ra = $d->value($r[0]);
$rb = $d->value($r[1]);
echo sprintf("%d/%d reduces to %d/%d\n", $a, $b, $ra, $rb);
実行してみましょう。
php -f UseDivisor.php > UseDivisor.txt
example/UseDivisor.txt というファイルができているので、中を見てみましょう。
12 has 6 divisors.
[1, 2, 3, 4, 6, 12]
12 = 2 ^ 2 * 3
18 = 2 * 3 ^ 2
common factors : 2 * 3
common divisors : [1, 2, 3, 6]
greatest common factor (divisor) : 6
12/18 reduces to 2/3
これも見れば大体内容がわかると思います。
面倒な箇所だけ掻い摘んで説明します。
$d->formula($d->value($d->commonFactors($a, $b)))
$d->commonFactors($a, $b) は、引数同士の共通因数を特殊な配列で返します。
例えば、12と18の共通因数は 2 * 3 ですが、次のような配列が返ります。
array(2){
[2] =>
int(1)
[3] =>
int(1)
}
ハッシュキーが基数、ハッシュの値が指数となっています。
$d->value($d->commonFactors($a, $b)) は、この配列を基に数値を返します。
$d->formula($d->value($d->commonFactors($a, $b))) は、数値を基に素因数の積で式を返します。
Multiple.php の使用例
example/UseMultiple.php を開いて見てみましょう。
倍数関連の基本機能の使用例です。
<?php
require_once('../vendor/autoload.php');
use Macocci7\PhpMathInteger\Multiple;
$m = new Multiple();
$a = 12;
$b = 18;
// least common multiple
echo sprintf(
"least common multiple of %d and %d is %d\n",
$a,
$b,
$m->leastCommonMultiple($a, $b)
);
実行してみましょう。
php -f UseMultiple.php > UseMultiple.txt
example/UseMultiple.txt というファイルが出来ているので、開いて見てみましょう。
least common multiple of 12 and 18 is 36
特に説明は不要だと思います。
Euclid.php の使用例
example/UseEuclid.php を開いて見てみましょう。
ユークリッド互除法関連の基本機能の使用例です。
<?php
/**
* Examples of operation with
* Macocci7\PhpMathInteger\Euclid
*/
require_once('../vendor/autoload.php');
use Macocci7\PhpMathInteger\Euclid;
// Presets values
$e = new Euclid();
$a = 390;
$b = 273;
$c = 39;
// Judges if $c is GCD($a, $b) or not
echo sprintf(
"Is %d GCD(%d, %d)? - %s.\n",
$c,
$a,
$b,
$e->isGcdOf($c, $a, $b) ? 'Yes' : 'No'
);
// Euclidean Algorithm
$r = $e->run($a, $b);
echo "Euclidean Algorithm:\n";
foreach ($r['processText'] as $t) {
echo $t . "\n";
}
// Formula of remainders
echo "Remainders can be expressed as:\n";
foreach ($r['processData'] as $d) {
echo sprintf("%d = %d - %d * %d\n", $d['r'], $d['a'], $d['b'], $d['c']);
}
// Judges if $a and $b are coprime or not
echo sprintf(
"Are %d and %d coprime? - %s.\n",
$a,
$b,
$e->isCoprime($a, $b) ? 'Yes' : 'No'
);
// GCD($a, $b)
echo sprintf(
"Because the Greatest Common Divisor of %d and %d is %d.\n",
$a,
$b,
$e->gcd($a, $b)
);
実行してみましょう。
php -f UseEuclid.php > UseEuclid.txt
example/UseEuclid.txt というファイルが出来ているので、開いて見てみましょう。
Is 39 GCD(390, 273)? - Yes.
Euclidean Algorithm:
390 = 273 * 1 + 117
273 = 117 * 2 + 39
117 = 39 * 3 + 0
Remainders can be expressed as:
117 = 390 - 273 * 1
39 = 273 - 117 * 2
0 = 117 - 39 * 3
Are 390 and 273 coprime? - No.
Because the Greatest Common Divisor of 390 and 273 is 39.
これも見れば内容が大体わかると思いますが、
用語的に掻い摘んで説明しておくと、
coprime とは教科書上では「互いに素」という言葉です。
「a と b が互いに素」とは、「a と b の最大公約数が1のみ」
ということです。ただし、a ≠ b です。
互いに素の組み合わせ例:
(a, b) = (1, 2), (2, 3), (3, 4), (4, 5), …, (8, 9), …
Bezout.php の使用例
example/UseBezout.php を開いて見てみましょう。
(2元1次)不定方程式(ベズーの等式)関連の基本機能の使用例です。
<?php
/**
* Examples of operation with
* Macocci7\PhpMathInteger\Bezout
*/
require_once('../vendor/autoload.php');
use Macocci7\PhpMathInteger\Bezout;
// Bezout's Equation: 3x + 4y = 1
$b = new Bezout([3, 4, 1, ]);
echo sprintf("Bezout's Equation: %s\n", $b->equation());
// Solvable or not
echo sprintf("Is it solvable? - %s.\n", ($b->isSolvable() ? 'Yes' : 'No'));
// A solution set
$s = $b->solution()['solution'];
echo sprintf("A solutionset: (x, y) = (%d, %d)\n", $s['x'], $s['y']);
// General solution
$g = $b->generalSolution()['generalSolution']['formula'];
echo sprintf("General solution:\n\t%s\n\t%s\n", $g['x'], $g['y']);
実行してみましょう。
php -f UseBezout.php > UseBezout.txt
example/UseBezout.txt というファイルが出来ているので、開いて見てみましょう。
Bezout's Equation: 3x + 4y = 1
Is it solvable? - Yes.
A solutionset: (x, y) = (-1, 1)
General solution:
x = 4k - 1
y = 3k + 1
これも見れば大体内容がわかると思います。
※本来、ベズーの等式の英訳は Bezout’s Identity です。
Fraction.php の使用例
example/UseFraction.php を開いて見てみましょう。
分数関連の基本機能の使用例です。(おまけ機能です)
<?php
require_once('../vendor/autoload.php');
use Macocci7\PhpMathInteger\Fraction;
// prest: 1 and 2/4
$f = new Fraction('1 2/4');
// is reduced or not?
echo $f->text() . " is " . ($f->isReduced() ? '' : 'not ') . "reduced.\n";
// is proper or not?
echo $f->text() . " is " . ($f->isProper() ? '' : 'not ') . "a proper fraction.\n";
// is improper or not?
echo $f->text() . " is " . ($f->isImproper() ? '' : 'not ') . "a improper fraction.\n";
// is mixed or not?
echo $f->text() . " is " . ($f->isMixed() ? '' : 'not ') . "a mixed fraction.\n";
// convert $f into a improper fraction
echo $f->text() . " = " . $f->improper()->text() . "\n";
// convert $f into a mixed fraction
echo $f->text() . " = " . $f->mixed()->text() . "\n";
// reduce fraction
echo $f->text() . " reduces to " . $f->reduce()->text() . "\n";
// integral part
echo "integral part of " . $f->text() . " is " . $f->int() . "\n";
// change into a float
echo $f->text() . " = " . $f->float() . "\n";
// four arithmetic operations
$f1 = new Fraction('1/3');
$f2 = new Fraction('1/6');
echo $f1->text() . ' + ' . $f2->text() . ' = ' . $f1->add($f2)->text() . "\n";
$f1->set('2/3');
$f2->set('1/6');
echo $f1->text() . ' - ' . $f2->text() . ' = ' . $f1->substruct($f2)->text() . "\n";
$f1->set('2/3');
$f2->set('1/6');
echo $f1->text() . ' * ' . $f2->text() . ' = ' . $f1->multiply($f2)->text() . "\n";
$f1->set('2/3');
$f2->set('1/6');
echo $f1->text() . ' / ' . $f2->text() . ' = ' . $f1->divide($f2)->text() . "\n";
// reduce fractions to a common denominator
$f1->set('1/3');
$f2->set('2/5');
echo "reduce the fractions of " . $f1->text() . " and " . $f2->text()
. " to a common denominator:\n";
$f1->toCommonDenominator($f2);
echo $f1->text() . " and " . $f2->text() . "\n";
実行してみましょう。
php -f UseFraction.php > UseFraction.txt
example/UseFraction.txt というファイルが出来ているので、開いて見てみましょう。
1 2/4 is not reduced.
1 2/4 is not a proper fraction.
1 2/4 is not a improper fraction.
1 2/4 is a mixed fraction.
1 2/4 = 6/4
6/4 = 1 2/4
1 2/4 reduces to 1 1/2
integral part of 1 1/2 is 1
1 1/2 = 1.5
1/3 + 1/6 = 1/2
2/3 - 1/6 = 1/2
2/3 * 1/6 = 1/9
2/3 / 1/6 = 4/1
reduce the fractions of 1/3 and 2/5 to a common denominator:
5/15 and 6/15
これも見れば大体内容がわかると思いますが、
用語的に掻い摘んで説明していきます。
「1 2/4」の表記は日本語では見かけませんね。
これは帯分数の「1と4分の2」のことです。
「is reduced」は「既約分数である」ということです。
「proper fraction」は分子が分母より小さい分数。
「improper fraction」は分子が分母より大きい仮分数。
「mixed fraction」は帯分数。
「reduce the fractions to a common denominator」は「通分する」ということです。
今後の課題
- Number.php: まだ必要な機能がある。
- Multiple.php: まだ必要な機能がある。
- Fraction.php: 整数、少数との演算は?
- n進数の底変換が未実装
- 一般整数への対応は?
コメント