/*
** math.ops
*/
BEGIN_OPS_PREAMBLE
#include <math.h>
END_OPS_PREAMBLE
=head1 NAME
math.ops - Mathematical Opcodes
=cut
=head1 DESCRIPTION
Parrot's library of mathematical ops.
To use this library of ops, add this directive to your PIR:
.loadlib 'math_ops'
=cut
=head2 General Math
=over 4
=cut
########################################
=item B<cmod>(out INT, in INT, in INT)
=item B<cmod>(invar PMC, invar PMC, in INT)
=item B<cmod>(invar PMC, invar PMC, invar PMC)
NOTE: This "uncorrected mod" algorithm uses the C language's built-in
mod operator (x % y), which is
... the remainder when x is divided by y, and thus is zero
when y divides x exactly.
...
The direction of truncation for / and the sign of the result
for % are machine-dependent for negative operands, as is the
action taken on overflow or underflow.
-- [1], page 41
Also:
... if the second operand is 0, the result is undefined.
Otherwise, it is always true that (a/b)*b + a%b is equal to z. If
both operands are non-negative, then the remainder is non-
negative and smaller than the divisor; if not, it is guaranteed
only that the absolute value of the remainder is smaller than
the absolute value of the divisor.
-- [1], page 205
This op is provided for those who need it (such as speed-sensitive
applications with heavy use of mod, but using it only with positive
arguments), but a more mathematically useful mod based on ** floor(x/y)
and defined with y == 0 is provided by the mod op.
[1] Brian W. Kernighan and Dennis M. Ritchie, *The C Programming
Language*, Second Edition. Prentice Hall, 1988.
If the denominator is zero, a 'Divide by zero' exception is thrown.
=cut
inline op cmod(out INT, in INT, in INT) {
const INTVAL den = $3;
if ($3 == 0) {
opcode_t * const handler = Parrot_ex_throw_from_op_args(interp, expr NEXT(),
EXCEPTION_DIV_BY_ZERO,
"Divide by zero");
goto ADDRESS(handler);
}
$1 = $2 % den;
}
inline op cmod(invar PMC, invar PMC, in INT) {
INTVAL result;
if ($3 == 0) {
opcode_t * const handler = Parrot_ex_throw_from_op_args(interp, expr NEXT(),
EXCEPTION_DIV_BY_ZERO,
"Divide by zero");
goto ADDRESS(handler);
}
result = VTABLE_get_integer(interp, $2) % $3;
$1 = Parrot_pmc_new_init_int(interp, VTABLE_type(interp, $2), result);
}
inline op cmod(invar PMC, invar PMC, invar PMC) {
INTVAL result;
const INTVAL value = VTABLE_get_integer(interp, $3);
if (value == 0) {
opcode_t * const handler = Parrot_ex_throw_from_op_args(interp, expr NEXT(),
EXCEPTION_DIV_BY_ZERO,
"Divide by zero");
goto ADDRESS(handler);
}
result = VTABLE_get_integer(interp, $2) % value;
$1 = Parrot_pmc_new_init_int(interp, VTABLE_type(interp, $2), result);
}
########################################
=item B<cmod>(out NUM, in NUM, in NUM)
=item B<cmod>(invar PMC, invar PMC, in NUM)
NOTE: This "uncorrected mod" algorithm uses the built-in C math library's
fmod() function, which computes
... the remainder of dividing x by y. The return value is
x - n * y, where n is the quotient of x / y, rounded towards
zero to an integer.
-- fmod() manpage on RedHat Linux 7.0
In addition, fmod() returns
the remainder, unless y is zero, when the function fails and
errno is set.
According to page 251 of [1], the result when y is zero is implementation-
defined.
This op is provided for those who need it, but a more mathematically
useful numeric mod based on floor(x/y) instead of truncate(x/y) and
defined with y == 0 is provided by the mod op.
[1] Brian W. Kernighan and Dennis M. Ritchie, *The C Programming
Language*, Second Edition. Prentice Hall, 1988.
If the denominator is zero, a 'Divide by zero' exception is thrown.
=cut
inline op cmod(out NUM, in NUM, in NUM) {
const FLOATVAL den = $3;
if (FLOAT_IS_ZERO($3)) {
opcode_t * const handler = Parrot_ex_throw_from_op_args(interp, expr NEXT(),
EXCEPTION_DIV_BY_ZERO,
"Divide by zero");
goto ADDRESS(handler);
}
$1 = fmod($2, den);
}
inline op cmod(invar PMC, invar PMC, in NUM) {
FLOATVAL result;
const FLOATVAL value = $3;
if (FLOAT_IS_ZERO(value)) {
opcode_t * const handler = Parrot_ex_throw_from_op_args(interp, expr NEXT(),
EXCEPTION_DIV_BY_ZERO,
"Divide by zero");
goto ADDRESS(handler);
}
result = fmod(VTABLE_get_integer(interp, $2), value);
$1 = Parrot_pmc_new_init_int(interp,
VTABLE_type(interp, $2), (INTVAL)result);
}
=back
=cut
###############################################################################
=head2 Pseudorandom number operations
These operations perform various pseudorandom number operations.
=over 4
=item B<rand>(out NUM)
Set $1 to a random floating point number between 0 and 1, inclusive.
=cut
inline op rand(out NUM) {
$1 = Parrot_util_float_rand(0);
}
=item B<rand>(out INT)
Set $1 to a random integer between C<[-2^31, 2^31)> .
=cut
inline op rand(out INT) {
$1 = Parrot_util_int_rand(0);
}
=item B<rand>(out NUM, in NUM)
Set $1 to a random floating point number between 0 and $2, inclusive.
=cut
inline op rand(out NUM, in NUM) {
$1 = $2 * Parrot_util_float_rand(0);
}
=item B<rand>(out INT, in INT)
Set $1 to a integer between 0 and $2, inclusive.
=cut
inline op rand(out INT, in INT) {
$1 = Parrot_util_range_rand(0, $2, 0);
}
=item B<rand>(out NUM, in NUM, in NUM)
Set $1 to a random floating point number between $2 and $3, inclusive.
=cut
inline op rand(out NUM, in NUM, in NUM) {
$1 = $2 + ($3 - $2) * Parrot_util_float_rand(0);
}
=item B<srand>(in NUM)
Set the random number seed to $1. $1 is casted to an INTVAL.
=cut
inline op srand(in NUM) {
Parrot_util_srand((INTVAL)$1);
}
=item B<srand>(in INT)
Set the random number seed to $1.
=cut
inline op srand(in INT) {
Parrot_util_srand((INTVAL)$1);
}
=item B<rand>(out INT, in INT, in INT)
Set $1 to a integer between $2 and $3, inclusive.
=cut
inline op rand(out INT, in INT, in INT) {
$1 = Parrot_util_range_rand($2, $3, 0);
}
=back
=cut
=head1 COPYRIGHT
Copyright (C) 2001-2011, Parrot Foundation.
=head1 LICENSE
This program is free software. It is subject to the same license
as the Parrot interpreter itself.
=cut
/*
* Local variables:
* c-file-style: "parrot"
* End:
* vim: expandtab shiftwidth=4 cinoptions='\:2=2' :
*/