rightMultiplyByDoubling
Applies multiplication-by-doubling algorithm (a.k.a. exponentiation by squaring) to multiply argument arg by integer multiplier if multiplier is positive, multiply -arg
by multiplier if multiplier is negative, or return lazyZero()
if multiplier is zero.
For example here are resulting expressions for the following values of multiplier:
If
multiplier == 0
, the result islazyZero()
.If
multiplier == 1
, the result isadditionOp(base, arg)
.If
multiplier == 2
, the result isadditionOp(base, additionOp(arg, arg))
.If
multiplier == 3
, the result isadditionOp(additionOp(base, arg), additionOp(arg, arg))
.If
multiplier == 4
, the result isadditionOp(base, additionOp(additionOp(arg, arg), additionOp(arg, arg)))
.If
multiplier == -1
, the result isadditionOp(base, negationOp(arg))
.If
multiplier == -2
, the result isadditionOp(base, additionOp(negationOp(arg), negationOp(arg)))
.If
multiplier == -3
, the result isadditionOp(additionOp(base, negationOp(arg)), additionOp(negationOp(arg), negationOp(arg)))
.If
multiplier == -4
, the result isadditionOp(base, additionOp(additionOp(negationOp(arg), negationOp(arg)), additionOp(negationOp(arg), negationOp(arg))))
.And so on...
But actually such sub-expression like additionOp(arg, arg)
are not calculated several times. Instead of additionOp(additionOp(arg, arg), additionOp(arg, arg))
actual computation is equivalent to additionOp(arg, arg).let { additionOp(it, it) }
that uses 2 calls of additionOp
instead of three.
So one can say that additionOp is used \(O(\log(\mathrm{multiplier}))\) times.
Applies multiplication-by-doubling algorithm (a.k.a. exponentiation by squaring) to multiply argument arg by integer multiplier or return result of lazyZero if multiplier is 0uL
.
For example here are resulting expressions for the following values of multiplier:
If
multiplier == 0u
, the result islazyZero()
.If
multiplier == 1u
, the result isadditionOp(arg, arg)
.If
multiplier == 2u
, the result isadditionOp(arg, additionOp(arg, arg))
.If
multiplier == 3u
, the result isadditionOp(additionOp(arg, arg), additionOp(arg, arg))
.If
multiplier == 4u
, the result isadditionOp(arg, additionOp(additionOp(arg, arg), additionOp(arg, arg)))
.And so on...
But actually such sub-expression like additionOp(arg, arg)
are not calculated several times. Instead of additionOp(additionOp(arg, arg), additionOp(arg, arg))
actual computation is equivalent to additionOp(arg, arg).let { additionOp(it, it) }
that uses two calls of additionOp
instead of three.
So one can say that additionOp is used \(O(\log(\mathrm{multiplier}))\) times.
Applies multiplication-by-doubling algorithm (a.k.a. exponentiation by squaring) to multiply argument arg by integer multiplier if multiplier is positive, multiply -arg
by multiplier if multiplier is negative, or return lazyZero()
if multiplier is zero.
For example here are resulting expressions for the following values of multiplier:
If
multiplier == 0L
, the result islazyZero()
.If
multiplier == 1L
, the result isadditionOp(base, arg)
.If
multiplier == 2L
, the result isadditionOp(base, additionOp(arg, arg))
.If
multiplier == 3L
, the result isadditionOp(additionOp(base, arg), additionOp(arg, arg))
.If
multiplier == 4L
, the result isadditionOp(base, additionOp(additionOp(arg, arg), additionOp(arg, arg)))
.If
multiplier == -1L
, the result isadditionOp(base, negationOp(arg))
.If
multiplier == -2L
, the result isadditionOp(base, additionOp(negationOp(arg), negationOp(arg)))
.If
multiplier == -3L
, the result isadditionOp(additionOp(base, negationOp(arg)), additionOp(negationOp(arg), negationOp(arg)))
.If
multiplier == -4L
, the result isadditionOp(base, additionOp(additionOp(negationOp(arg), negationOp(arg)), additionOp(negationOp(arg), negationOp(arg))))
.And so on...
But actually such sub-expression like additionOp(arg, arg)
are not calculated several times. Instead of additionOp(additionOp(arg, arg), additionOp(arg, arg))
actual computation is equivalent to additionOp(arg, arg).let { additionOp(it, it) }
that uses 2 calls of additionOp
instead of three.
So one can say that additionOp is used \(O(\log(\mathrm{multiplier}))\) times.
Applies multiplication-by-doubling algorithm (a.k.a. exponentiation by squaring) to multiply argument arg by integer multiplier or return result of lazyZero if multiplier is 0uL
.
For example here are resulting expressions for the following values of multiplier:
If
multiplier == 0uL
, the result islazyZero()
.If
multiplier == 1uL
, the result isadditionOp(arg, arg)
.If
multiplier == 2uL
, the result isadditionOp(arg, additionOp(arg, arg))
.If
multiplier == 3uL
, the result isadditionOp(additionOp(arg, arg), additionOp(arg, arg))
.If
multiplier == 4uL
, the result isadditionOp(arg, additionOp(additionOp(arg, arg), additionOp(arg, arg)))
.And so on...
But actually such sub-expression like additionOp(arg, arg)
are not calculated several times. Instead of additionOp(additionOp(arg, arg), additionOp(arg, arg))
actual computation is equivalent to additionOp(arg, arg).let { additionOp(it, it) }
that uses two calls of additionOp
instead of three.
So one can say that additionOp is used \(O(\log(\mathrm{multiplier}))\) times.