# How to replicate % operator in simple driver expressions?

Since Python's modulo operator % isn't available in Simple Expressions:

Blender can evaluate a useful subset of Python driver expressions directly, which significantly improves performance, especially on multi-core systems.

Since Python drivers are considerably slower how would one port a Python formula using % modulo operator, to use fmod function (or something else?) instead?

Below a testing script to compare % operator with fmod function:

from math import fmod

def fakemod(a, n):
return fmod(a, n)

row = "| {:>7} " * 5 + "|"

print(line)
print(header.format(" ", "     ", "fakemod", "     ", "fakemod"))
print(header.format("i", "i % 4", "(i, 4)", "i % -4", "(i, -4)"))
print(line)
equal = lambda a,b: '==' if a == b else '!='
for i in range(-10, 10):
a, b, c, d = i % 4, fakemod(i, 4), i % -4, fakemod(i, -4)
print(row.format(i, a, f"{equal(a,b)} {b}", c, f"{equal(c,d)} {d}"))
print(line)


I'm looking for a way to remove the inconsistencies between % and fakemod. For readability I mark the inconsistencies with != below:

+---------+---------+---------+---------+---------+
|         |         | fakemod |         | fakemod |
|    i    |  i % 4  | (i, 4)  | i % -4  | (i, -4) |
+---------+---------+---------+---------+---------+
|     -10 |       2 | != -2.0 |      -2 | == -2.0 |
|      -9 |       3 | != -1.0 |      -1 | == -1.0 |
|      -8 |       0 | == -0.0 |       0 | == -0.0 |
|      -7 |       1 | != -3.0 |      -3 | == -3.0 |
|      -6 |       2 | != -2.0 |      -2 | == -2.0 |
|      -5 |       3 | != -1.0 |      -1 | == -1.0 |
|      -4 |       0 | == -0.0 |       0 | == -0.0 |
|      -3 |       1 | != -3.0 |      -3 | == -3.0 |
|      -2 |       2 | != -2.0 |      -2 | == -2.0 |
|      -1 |       3 | != -1.0 |      -1 | == -1.0 |
|       0 |       0 |  == 0.0 |       0 |  == 0.0 |
|       1 |       1 |  == 1.0 |      -3 |  != 1.0 |
|       2 |       2 |  == 2.0 |      -2 |  != 2.0 |
|       3 |       3 |  == 3.0 |      -1 |  != 3.0 |
|       4 |       0 |  == 0.0 |       0 |  == 0.0 |
|       5 |       1 |  == 1.0 |      -3 |  != 1.0 |
|       6 |       2 |  == 2.0 |      -2 |  != 2.0 |
|       7 |       3 |  == 3.0 |      -1 |  != 3.0 |
|       8 |       0 |  == 0.0 |       0 |  == 0.0 |
|       9 |       1 |  == 1.0 |      -3 |  != 1.0 |
+---------+---------+---------+---------+---------+

• I think an example workflow to place this feature in the context of Blender would be nice, currently I feel like only the people who would know how to solve this problem may understand the question :) Commented Oct 27, 2022 at 6:44
• @Gorgious Well I lost some time figuring this out, unable to google the existing solution… I also got it wrong in the past because I tested lazily. Commented Oct 27, 2022 at 10:29

def fakemod(a, n):
return fmod(fmod(a, n)+n, n)


Result:

+---------+---------+---------+---------+---------+
|         |         | fakemod |         | fakemod |
|    i    |  i % 4  | (i, 4)  | i % -4  | (i, -4) |
+---------+---------+---------+---------+---------+
|     -10 |       2 |  == 2.0 |      -2 | == -2.0 |
|      -9 |       3 |  == 3.0 |      -1 | == -1.0 |
|      -8 |       0 |  == 0.0 |       0 | == -0.0 |
|      -7 |       1 |  == 1.0 |      -3 | == -3.0 |
|      -6 |       2 |  == 2.0 |      -2 | == -2.0 |
|      -5 |       3 |  == 3.0 |      -1 | == -1.0 |
|      -4 |       0 |  == 0.0 |       0 | == -0.0 |
|      -3 |       1 |  == 1.0 |      -3 | == -3.0 |
|      -2 |       2 |  == 2.0 |      -2 | == -2.0 |
|      -1 |       3 |  == 3.0 |      -1 | == -1.0 |
|       0 |       0 |  == 0.0 |       0 | == -0.0 |
|       1 |       1 |  == 1.0 |      -3 | == -3.0 |
|       2 |       2 |  == 2.0 |      -2 | == -2.0 |
|       3 |       3 |  == 3.0 |      -1 | == -1.0 |
|       4 |       0 |  == 0.0 |       0 | == -0.0 |
|       5 |       1 |  == 1.0 |      -3 | == -3.0 |
|       6 |       2 |  == 2.0 |      -2 | == -2.0 |
|       7 |       3 |  == 3.0 |      -1 | == -1.0 |
|       8 |       0 |  == 0.0 |       0 | == -0.0 |
|       9 |       1 |  == 1.0 |      -3 | == -3.0 |
+---------+---------+---------+---------+---------+

• Back in the day.. not needed any more, in nodes, with Wrap. But.. how come I got % to work in the expression in my comment here? Commented Oct 27, 2022 at 7:42
• Oh Rich Sedman came up with exactly the same solution, nice! I tried googling "implement Python's modulo using fmod" etc. but never found something concise (and drivers really need conciseness). As for why you have no problem using % - drivers work in 3 modes: Blender first tries to tokenize an expression for its own stack machine, if it succeeds, you have a simple expression. % operator is not there, so using it will make Blender fail to tokenize and use a slow Python expression. Commented Oct 27, 2022 at 10:23
• @RobinBetts BTW when Python is used, first the names and opcodes are checked against a whitelist, if the check fails, you're asked for a permission to run a potentially dangerous script. Here's an interesting case showcasing that. I actually wrote this Q&A to relief some bloat from that answer. Commented Oct 27, 2022 at 10:26
• And only now I realized I misrepresented Chris'es solution there because I just represented % as modulo, whereas shading modulo uses fmod Commented Oct 27, 2022 at 10:43
• MVB: Wow! That is such a complete response! (Like your answers, of late).. Thanks! :) Commented Oct 27, 2022 at 11:32

I know that the topic is closed, but I want to add something for future readers, cause I found a simple solution to use modulos in a Blender scripted expression. So maybe that can help ?

Replace **i%4** by **i-i//4**

For exemple, for i = 406 (406%4 = **2**) :

406-406//4 = **2**

406-(101x4) = **2**

406-404 = **2**

• Welcome to BSE! Unfortunately, as simple as this answer is, it seems incorrect: let's assume $i = 4$, then we expect $4 \% 4 = 0$, whereas your solution 4 - 4 // 4 will evaluate to 4 - 1 which will evaluate to 3. You have a unit test prepared in the question, just replace fakemod function's body with return a-a//n and you will see the result: i.imgur.com/XljD9mj.png Also, topics are never closed (from old age) on Stack Exchange, feel free to add an answer, suggest an edit, comment etc. after decades. Commented Nov 19, 2023 at 10:39
• Hello ! Thanks for your reply ! I hadn't noticed this error because in my use this case couldn't occur. the behavior changed if a=n. So it seemed perfect to me. Thank you for your help ! Commented Nov 30, 2023 at 21:04