# 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 :) 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. 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? 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. 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. 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 Oct 27, 2022 at 10:43
• MVB: Wow! That is such a complete response! (Like your answers, of late).. Thanks! :) 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. 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 ! Nov 30, 2023 at 21:04