by jeeswg » 19 May 2019, 18:39
Here is some code for a potential FloorMod function.
Code: Select all
==================================================
for AHK v1: function names and parameters:
[Mod] FloorMod(Dividend, Divisor)
- note: BIF_Mod would be amended
- note: it's generally more useful to have a Mod function always return a positive number (or zero)
- note: works likes Java's floorMod function and Python's % operator
- note: the sign of the result is based on the sign of the divisor
- note: the function adds the divisor if necessary, to ensure the sign
- note: perhaps a more complicated, purer, mathematical solution is needed
==================================================
[script.h]
[no changes needed]
==================================================
[script.cpp]
else if (!_tcsicmp(func_name, _T("Mod")) || !_tcsicmp(func_name, _T("FloorMod")))
//else if (!_tcsicmp(func_name, _T("Mod")))
{
bif = BIF_Mod;
min_params = 2;
max_params = 2;
}
==================================================
[script2.cpp]
BIF_DECL(BIF_Mod)
{
bool is_floormod = (ctoupper(aResultToken.marker[0]) == 'F');
// Load-time validation has already ensured there are exactly two parameters.
// "Cast" each operand to Int64/Double depending on whether it has a decimal point.
ExprTokenType param0, param1;
if (!ParamIndexToNumber(0, param0) || !ParamIndexToNumber(1, param1)) // Non-operand or non-numeric string.
{
aResultToken.symbol = SYM_STRING;
aResultToken.marker = _T("");
return;
}
if (param0.symbol == SYM_INTEGER && param1.symbol == SYM_INTEGER)
{
if (!param1.value_int64) // Divide by zero.
{
aResultToken.symbol = SYM_STRING;
aResultToken.marker = _T("");
}
else
{
// For performance, % is used vs. qmath for integers.
// Caller has set aResultToken.symbol to a default of SYM_INTEGER, so no need to set it here.
aResultToken.value_int64 = param0.value_int64 % param1.value_int64;
if (is_floormod)
if ((param1.value_int64 > 0 && aResultToken.value_int64 < 0) || (param1.value_int64 < 0 && aResultToken.value_int64 > 0))
aResultToken.value_int64 += param1.value_int64;
}
}
else // At least one is a floating point number.
{
double dividend = TokenToDouble(param0);
double divisor = TokenToDouble(param1);
if (divisor == 0.0) // Divide by zero.
{
aResultToken.symbol = SYM_STRING;
aResultToken.marker = _T("");
}
else
{
aResultToken.symbol = SYM_FLOAT;
aResultToken.value_double = qmathFmod(dividend, divisor);
if (is_floormod)
if ((divisor > 0 && aResultToken.value_double < 0) || (divisor < 0 && aResultToken.value_double > 0))
aResultToken.value_double += divisor;
}
}
}
==================================================
Relevant AHK code:
[FloorDiv/FloorMod(/ModPsv)]
FloorDiv / FloorMod (and an 'always positive' Mod function) - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=6&t=55751
Here is some code for a potential FloorMod function.
[code=cpp]
==================================================
for AHK v1: function names and parameters:
[Mod] FloorMod(Dividend, Divisor)
- note: BIF_Mod would be amended
- note: it's generally more useful to have a Mod function always return a positive number (or zero)
- note: works likes Java's floorMod function and Python's % operator
- note: the sign of the result is based on the sign of the divisor
- note: the function adds the divisor if necessary, to ensure the sign
- note: perhaps a more complicated, purer, mathematical solution is needed
==================================================
[script.h]
[no changes needed]
==================================================
[script.cpp]
else if (!_tcsicmp(func_name, _T("Mod")) || !_tcsicmp(func_name, _T("FloorMod")))
//else if (!_tcsicmp(func_name, _T("Mod")))
{
bif = BIF_Mod;
min_params = 2;
max_params = 2;
}
==================================================
[script2.cpp]
BIF_DECL(BIF_Mod)
{
bool is_floormod = (ctoupper(aResultToken.marker[0]) == 'F');
// Load-time validation has already ensured there are exactly two parameters.
// "Cast" each operand to Int64/Double depending on whether it has a decimal point.
ExprTokenType param0, param1;
if (!ParamIndexToNumber(0, param0) || !ParamIndexToNumber(1, param1)) // Non-operand or non-numeric string.
{
aResultToken.symbol = SYM_STRING;
aResultToken.marker = _T("");
return;
}
if (param0.symbol == SYM_INTEGER && param1.symbol == SYM_INTEGER)
{
if (!param1.value_int64) // Divide by zero.
{
aResultToken.symbol = SYM_STRING;
aResultToken.marker = _T("");
}
else
{
// For performance, % is used vs. qmath for integers.
// Caller has set aResultToken.symbol to a default of SYM_INTEGER, so no need to set it here.
aResultToken.value_int64 = param0.value_int64 % param1.value_int64;
if (is_floormod)
if ((param1.value_int64 > 0 && aResultToken.value_int64 < 0) || (param1.value_int64 < 0 && aResultToken.value_int64 > 0))
aResultToken.value_int64 += param1.value_int64;
}
}
else // At least one is a floating point number.
{
double dividend = TokenToDouble(param0);
double divisor = TokenToDouble(param1);
if (divisor == 0.0) // Divide by zero.
{
aResultToken.symbol = SYM_STRING;
aResultToken.marker = _T("");
}
else
{
aResultToken.symbol = SYM_FLOAT;
aResultToken.value_double = qmathFmod(dividend, divisor);
if (is_floormod)
if ((divisor > 0 && aResultToken.value_double < 0) || (divisor < 0 && aResultToken.value_double > 0))
aResultToken.value_double += divisor;
}
}
}
==================================================
[/code]
Relevant AHK code:
[FloorDiv/FloorMod(/ModPsv)]
FloorDiv / FloorMod (and an 'always positive' Mod function) - AutoHotkey Community
[url]https://autohotkey.com/boards/viewtopic.php?f=6&t=55751[/url]