Page 1 of 1

C++: AHK source code: FloorMod

Posted: 19 May 2019, 18:39
by jeeswg
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