/* *********************************************************************
This source file is a part of the standard library of Scol
For the latest info, see http://www.scolring.org
Copyright (c) 2013 Stephane Bisaro aka Iri.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
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. See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt
********************************************************************* */
/*
* Standard functions for mathematical objects
* See http://redmine.scolring.org/projects/tutorials/wiki/Scol_usage
* for more informations
*/
/*! \file maths.pkg
* \author Scol team
* \version 0.1
* \copyright GNU Lesser General Public License 2.0 or later
* \brief Scol Standard Library - Maths API
*
* \details This API provides some functions to manipulate some mathematical objects
*
* Dependancies :
* - lib/std/stdlib.pkg
*
**/
/* When Scol will support the larger integers, these constantes will be changed */
var STD_MFIBONACCI = 43;;
var STD_M2POWER = 127.0;;
var STD_M2POWERI = 29;;
fun std_mfibonacci (n, o1, o2)=
if n == 0 then
o2
else
let _fooS strcat itoa n strcat " " itoa o2 -> _ in
std_mfibonacci n-1 o2 o2+o1;;
/*
fun std_mfibonaccif (n, o1, o2)=
if std_fIsZero n then
o2
else
let _fooS strcat ftoa n strcat " " ftoa o2 -> _ in
std_mfibonaccif n-.1.0 o2 o2+.o1;;
fun std_mFibonacciF (n)=
let std_mfibonacci absf itof n 0.0 1.0 -> r in
if ((n < 0) && (!mod n 2)) then
(-.r)
else
r;;
*/
/*! \brief Return the nth value of the Fibonacci series
* (1, 1, 2, 3, 5, 8, 13, 21, ...)
*
* \remark Negative numbers are supported.
* \ingroup std_math
* Prototype : : fun [I] I
*
* \param I : an integer (-43 to 43 included)
* \return I : the result or nil if out of range
**/
fun std_mFibonacci (n)=
if STD_MFIBONACCI < abs n then
nil
else
let std_mfibonacci abs n 0 1 -> r in
if ((n < 0) && (!mod n 2)) then // negatif et paire
(-r)
else
r;;
/*! \brief Return the power of two : \f$2^{f}\f$
*
* \remark Negative numbers are NOT supported.
*
* \ingroup std_math
* Prototype : : fun [F] F
*
* \param F : a float number (0 to 127 included)
* \return F : the result or nil if out of range
**/
fun std_m2power (x)=
if (x >. STD_M2POWER) && (x >=. 0.0) then
nil
else
pow 2.0 x;;
/*! \brief Return the power of two : \f$2^{i}\f$
*
* \remark Negative numbers are NOT supported.
*
* \ingroup std_math
* Prototype : : fun [I] I
*
* \param I : a float number (0 to 29 included)
* \return I : the result or nil if out of range
**/
fun std_m2powerI (x)=
if (x > STD_M2POWERI) && (x >= 0) then
nil
else
ftoi pow 2.0 itof x;;
/*! \brief Convert degree to radian
*
* \ingroup std_math
* Prototype : : fun [F] F
*
* \param F : a value in degree
* \return F : the same value in radian
**/
fun std_mDegToRad (f)=
mulf f ((2.0 *. PIf) /. 360.0);;
/*! \brief Convert radian to degree
*
* \ingroup std_math
* Prototype : : fun [F] F
*
* \param F : a value in radian
* \return F : the same value in degree
**/
fun std_mRadToDeg (f)=
divf f ((2.0 *. PIf) /. 360.0);;
/*! \brief Return the GCD (Greatest Common Divisor, PGCD in french) of
* two integers
*
* \ingroup std_math
* Prototype : : fun [I I] I
*
* \param I : a first integer
* \param I : a second integer
* \return I : the GCD
**/
fun std_mGCD (int1, int2)=
if int2 == 0 then
int1
else
std_mGCD int2 mod int1 int2;;
/*! \brief Return the LCM (Least Common Multiple, PPCM in french) of
* two integers
*
* \ingroup std_math
* Prototype : : fun [I I] I
*
* \param I : a first integer
* \param I : a second integer
* \return I : the LCM
**/
fun std_mLCM (int1, int2)=
if (int1 == 0) || (int2 == 0) then
0
else
(int1 * int2) / (std_mGCD int1 int2);;
/*! \brief Calculate the power of an integer by a quick recursion
*
* \ingroup std_math
* Prototype : : fun [I I] I
*
* \param I : an integer
* \param I : a power (should be >= 0 otherwise, nil will be returned)
* \return I : the result or nil if error
**/
fun std_mPow (i, n)=
if n < 0 then
nil
else
if n == 0 then
1
else if n == 1 then
i
else
let std_mPow i n/2 -> t in
if 0 == mod n 2 then
t*t
else
i*t*t;;
fun STD_M_PRIME () = 1;;
fun STD_M_COMPOSITE () = 0;;
// Write (n - 1) as 2^s * d
fun std_mprimality_step1 (s, d)=
if (mod d 2) == 0 then
std_mprimality_step1 s+1 d/2
else
[s d];;
/*fun std_mprimality_step2 (n)=
if (n == 2) || (n == 3) then
STD_M_PRIME
else if (mod n 2) || (n < 2) then
STD_M_COMPOSITE
else
let std_mprimality_step1 0 n-1 -> [s d] in
let std_random */
// calcul a^b%c
fun std_mprime_mr_power (a, b, c)=
let 1 -> out in
(
while (b) do
(
if (b&1) then
set out = mod (out * a) c
else
0;
set a = mod (a * a) c;
set b = b>>1;
);
out
);;
// n−1 = 2^s * d with d odd by factoring powers of 2 from n−1
fun std_mprime_mr_witness (n, s, d, a)=
let std_mprime_mr_power a d n -> x in
let nil -> out in
let 0 -> y in
(
while s do
(
set y = mod (x * x) n;
if (y == 1) && (x != 1) && (x != n-1) then
set out = STD_M_COMPOSITE
else
0;
set x = y;
set s = s-1;
);
if out != nil then
out
else
if y != 1 then
STD_M_COMPOSITE
else
STD_M_PRIME
);;
fun std_mprime_mr_det (n)=
if (((!(n & 1)) && (n != 2)) || (n < 2) || ((0 == mod n 3) && (n != 3))) then
STD_M_COMPOSITE
else if (n <= 3) then
STD_M_PRIME
else
let n / 2 -> d in
let 1 -> s in
(
while (!(d & 1)) do
(
set d = d / 2;
set s = s + 1
);
if n < 1373653 then
(std_mprime_mr_witness n s d 2) && (std_mprime_mr_witness n s d 3)
else if n < 9080191 then
(std_mprime_mr_witness n s d 31) && (std_mprime_mr_witness n s d 73)
else // for supported integers by Scol (type : I), in fact else if n < 4759123141 then
(std_mprime_mr_witness n s d 2) && (std_mprime_mr_witness n s d 7) && (std_mprime_mr_witness n s d 71)
/* here greater number than 4759123141
else if n < 1122004669633 then
(std_mprime_mr_witness n s d 2) && (std_mprime_mr_witness n s d 13) && (std_mprime_mr_witness n s d 23) && (std_mprime_mr_witness n s d 1662803)
else if n < 2152302898747 then
(std_mprime_mr_witness n s d 2) && (std_mprime_mr_witness n s d 3) && (std_mprime_mr_witness n s d 5) && (std_mprime_mr_witness n s d 7) && (std_mprime_mr_witness n s d 11)
else if n < 3474749660383 then
(std_mprime_mr_witness n s d 2) && (std_mprime_mr_witness n s d 3) && (std_mprime_mr_witness n s d 5) && (std_mprime_mr_witness n s d 7) && (std_mprime_mr_witness n s d 11) && (std_mprime_mr_witness n s d 13)
else // until 341550071728321
(std_mprime_mr_witness n s d 2) && (std_mprime_mr_witness n s d 3) && (std_mprime_mr_witness n s d 5) && (std_mprime_mr_witness n s d 7) && (std_mprime_mr_witness n s d 11) && (std_mprime_mr_witness n s d 13) && (std_mprime_mr_witness n s d 17)
*/
);;
/*! \brief Returns if an integer is a prime number or a composite number.
*
* This is a deterministic implementation of the Miller-Rabin primality
* algorithm.
*
* \ingroup std_math
* Prototype : : fun [I] I
*
* \param I : an integer
* \return I : STD_M_COMPOSITE if number is composite, STD_M_PRIME if
* number is a strong probably prime or nil if error
**/
fun std_mPrimeMRDet (iNumber)=
if std_objIsNil iNumber then
nil
else
std_mprime_mr_det iNumber;;