Math.sin() is giving me Math Domain Error
Question:
I am making a program to create an image of the mandelbrot set as a .ppm file.
I tried implementing a rudimentary version of "normalized iteration count", when math.sin() started giving me a math domain error.
Math.sin() shouldn’t have a domain, right? I’m stumped…
import math
def ask(question):
return float(input(question))
maxIts=ask("max iterations? ")
size=int(ask("image side length? "))
sideTuple=(round(-size/2),round(size/2))
ppmFile=["P3",str(size),str(size),"255"]
def getV(z,n):
return n-math.log2(math.log10(z))
def addValue(v):
for i in range(0,3):
ppmFile.append(str(math.sin(v)))
def iterate(x,y):
coord=complex(x,y)
i=0
z=coord
while i<maxIts and z.real<10:
z=(z*z)+coord
i+=1
if z.real>10:
addValue(getV(z.real,i))
else:
ppmFile.append("0 0 0")
def render(x,y,scale):
for j in range(*sideTuple):
for i in range(*sideTuple):
iterate(4*i/(scale*size)+x,4*j/(scale*size)-y)
render(ask("x position? "),ask("y position? "),ask("zoom? "))
newFile=open("brotPPM.ppm","w")
newFile.write(" ".join(ppmFile))
newFile.close
Putting in 256, 1000, 0, 0, and 1 as inputs gave me this:
Traceback (most recent call last):
File "C:UsersMeDownloadsPythonbrotPPM_v4.py", line 34, in <module>
render(ask("x position? "),ask("y position? "),ask("zoom? "))
File "C:UsersMeDownloadsPythonbrotPPM_v4.py", line 32, in render
iterate(4*i/(scale*size)+x,4*j/(scale*size)-y)
File "C:UsersMeDownloadsPythonbrotPPM_v4.py", line 24, in iterate
addValue(getV(z.real,i))
File "C:UsersMeDownloadsPythonbrotPPM_v4.py", line 13, in addValue
ppm.append(str(math.sin(v)))
^^^^^^^^^^^
ValueError: math domain error
Answers:
If you wrap addValue
in a try-catch statement, you can show what value of v
or what value of z
is the problem.
It turns out to be infinities. Sometimes, the real part of z
escapes to infinity, and then you’ll end up with an infinite value being passed to math.sin
. Consider mapping infinity to its own colour.
def getV(z, n):
v = n - math.log2(math.log10(z))
try:
return math.sin(v)
except ValueError:
return 42 # ??
def addValue(v):
for i in range(3):
ppmFile.append(str(v))
By the way, you don’t close the file at the end (unless you forgot to include the parentheses when pasting your code here), which may or may not end up being a problem. By using a context manager, you can be sure the file is closed at the end:
with open("brotPPM.ppm","w") as newFile:
newFile.write(" ".join(ppmFile))
I am making a program to create an image of the mandelbrot set as a .ppm file.
I tried implementing a rudimentary version of "normalized iteration count", when math.sin() started giving me a math domain error.
Math.sin() shouldn’t have a domain, right? I’m stumped…
import math
def ask(question):
return float(input(question))
maxIts=ask("max iterations? ")
size=int(ask("image side length? "))
sideTuple=(round(-size/2),round(size/2))
ppmFile=["P3",str(size),str(size),"255"]
def getV(z,n):
return n-math.log2(math.log10(z))
def addValue(v):
for i in range(0,3):
ppmFile.append(str(math.sin(v)))
def iterate(x,y):
coord=complex(x,y)
i=0
z=coord
while i<maxIts and z.real<10:
z=(z*z)+coord
i+=1
if z.real>10:
addValue(getV(z.real,i))
else:
ppmFile.append("0 0 0")
def render(x,y,scale):
for j in range(*sideTuple):
for i in range(*sideTuple):
iterate(4*i/(scale*size)+x,4*j/(scale*size)-y)
render(ask("x position? "),ask("y position? "),ask("zoom? "))
newFile=open("brotPPM.ppm","w")
newFile.write(" ".join(ppmFile))
newFile.close
Putting in 256, 1000, 0, 0, and 1 as inputs gave me this:
Traceback (most recent call last):
File "C:UsersMeDownloadsPythonbrotPPM_v4.py", line 34, in <module>
render(ask("x position? "),ask("y position? "),ask("zoom? "))
File "C:UsersMeDownloadsPythonbrotPPM_v4.py", line 32, in render
iterate(4*i/(scale*size)+x,4*j/(scale*size)-y)
File "C:UsersMeDownloadsPythonbrotPPM_v4.py", line 24, in iterate
addValue(getV(z.real,i))
File "C:UsersMeDownloadsPythonbrotPPM_v4.py", line 13, in addValue
ppm.append(str(math.sin(v)))
^^^^^^^^^^^
ValueError: math domain error
If you wrap addValue
in a try-catch statement, you can show what value of v
or what value of z
is the problem.
It turns out to be infinities. Sometimes, the real part of z
escapes to infinity, and then you’ll end up with an infinite value being passed to math.sin
. Consider mapping infinity to its own colour.
def getV(z, n):
v = n - math.log2(math.log10(z))
try:
return math.sin(v)
except ValueError:
return 42 # ??
def addValue(v):
for i in range(3):
ppmFile.append(str(v))
By the way, you don’t close the file at the end (unless you forgot to include the parentheses when pasting your code here), which may or may not end up being a problem. By using a context manager, you can be sure the file is closed at the end:
with open("brotPPM.ppm","w") as newFile:
newFile.write(" ".join(ppmFile))