I've got some Python code that I'd like to understand what's going on (see below). I've got the results of the calculations as well.
If I square radius by repeated multiplication I get a different result than if I square radius. If it were rounding, I'd expect a smaller gap between the two calculations. Can someone put me on the right path, please?
import math
diameter=float(input('Enter the diameter: '))
radius = diameter / 2.0
area_1 = math.pi * radius * radius
print ("The area is: ", area_1)
area_2 = math.pi * radius**2
print ("The area is: ", area_2)
=========================================================
Enter the diameter: 6.2
The area is: 30.19070540099791**3**
The area is: 30.19070540099791**7**
The difference comes from the different way both expressions were calculated:
math.pi * radius * radius was calculated as:
a. tmp = math.pi * radius
b. tmp * radius
math.pi * radius**2
a. tmp2 = radius**2
b. tmp2 * math.pi
Mathematically both are equivalent but not so when we are talking about finite precision of floating point types in a computer.
You can read more on the topic on Wikipedia or other sources. The field of numerical analysis (and numerical methods) deals mostly with these numerical rounding errors in the pursue of finding best algorithms for involved calculations.
Related
I am making a library for math functions, intended to test and challenge my programming and math skills. A necessary part of this is trig: Sine, Cosine, Tangent, and derivatives/inverses, using degrees or radians.
I have spent hours searching the web for implementation of Taylor Series or CORDIC algorithm using degrees AND/OR radians, to no avail.
def sin(x):
if numerics.degrad == 'deg':
#compute sin(x) using degrees or radians, make sure to return the result in degrees
Please be informed, numerics.degrad is a string value to be referenced from any function in the library or terminal. Usual values are 'deg' or 'rad'. Also, I am trying to avoid importing libraries like numpy or math.
UPDATE: I tried today(11-12-19) to emulate sine by generating a parabola which intersected one waveform. The hope was to check which waveform the angle would land on, then use the according quadratic equation. That did not work. Results in DESMOS were off by up to 0.2 units, and my python implementation was just plain wrong.
# desmos implementation, where y is the output and x is the angle:
# y=0.0001234567901234(x-90)^2+1
# lays closely over a sine wave graphed with y=sin(x).
# here is my python implementation:
def sin(anglein): #return the result of sine of the supplied angle, using the mode
if degrad == 'deg':
const = 0.0001234567901234
angle = anglein
while angle > 360: #should return the corresponding angle within 0-360 degrees
angle -= 360
return((const * ((angle - 90) * (angle - 90))) + 1)
The Taylor series for the sin function is straightforward to implement. Note that any reference which gives a Taylor series for a trigonometric function will assume the input is in radians, unless specified otherwise.
PI = 3.141592653589793238462643383
def sin_taylor_series(x, terms=9):
# map x into the range -PI/2 to PI/2 for greatest accuracy
x %= 2*PI
if x > PI:
x -= 2*PI
if x < -PI/2:
x = -PI - x
elif x > PI/2:
x = PI - x
total = 0
denominator = 1
for i in range(1, 2*terms+2, 2):
denominator *= i
total += (x ** i) / denominator
denominator *= -(i + 1)
return total
At 9 terms, the max absolute error (compared with math.sin) is under 10 ** -15, which is about as good as you're going to get by adding a lot of floating point numbers together.
Note that this is not a particularly efficient way of approximating the sin function.
I'm struggling to work out how I move point A to B in an arc motion in 3D. The duration of the movement doesn't matter so much. I have found a load of wikipedia pages on it but am having no luck understanding them as its been a long time since I was in college. Any code examples would be really useful for me to understand. Thank you, I would really appreciate your help. Here is an image that sort of shows what I am looking to achieve, although the image only represents the points in 2d, I am looking for a 3d solution.
Assuming your problem statement is:
Given points a and b, trace the circular path along the plane which lies tangent to the up vector:
And that you have the appropriate vector algebra libraries:
def interp(a, b, up, t):
""" 0 <= t <= 1"""
# find center and radius vector
center = (a + b) / 2
radius = a - center
# split path into upwards and downwards section
omega = math.acos(radius.dot(up)) # angle between center-a and center-top
t_top = omega / math.pi # time taken to reach the top
# redefine 0 as A, 1 as the top, and B as whatever remains linear
t = t / t_top
#slerp, with t intentionally > 1
sin = math.sin
return (
center +
sin((1 - t) * omega) / sin(omega) * radius +
sin(t * omega) / sin(omega) * up
)
it doesnt matter if its 2d or 3d .
you take the position of each dot and find the center beetwean them .
the distance beetwean the center and each dot is the radius .
after that give the object a moving direction and tell it to be always in a distance of radius from center . which a moving vector you can give it any direction you want .
I was trying to find the values for the first ten integer inputs of n for an equation I found: x = sin(2π / n) / sin(π / n). The output I got from the code I wrote to find them was quite surprising:
>>> for i in range(1, 11):
print math.sin(2 * math.pi / i) / math.sin(math.pi / i)
-2.0
1.22464679915e-16
1.0
1.41421356237
1.61803398875
1.73205080757
1.8019377358
1.84775906502
1.87938524157
1.90211303259
I realise that there will be rounding errors, and as such the following results don't surprise me at all:
>>> math.sin(2 * math.pi)
-2.4492935982947064e-16
>>> math.sin(math.pi)
1.2246467991473532e-16
The question is, how did the first result end up with -2.0, I might expect it to return something close to zero or an error / nan?
If you are interested in knowing, this equation should give the length (x) of a line that stretches between one point and another point 2 points away in a shape with n equal sides of 1 and all equal angles (the length of the smallest diagonal of an isogon with side length 1).
For the second result, the impact is quite small in absolute terms: 1.22464679915e-16 is a very small number and very close to zero, about 0.00000000000000012246
If you simply want to avoid that small error having a large impact in how your results are displayed, use a formatting string, e.g:
for i in range(1, 11):
print "{0:.10f}".format(math.sin(2 * math.pi / i) / math.sin(math.pi / i))
output:
-2.0000000000
0.0000000000
1.0000000000
1.4142135624
1.6180339887
1.7320508076
1.8019377358
1.8477590650
1.8793852416
1.9021130326
how did the first result end up with -2.0, I might expect it to return something close to zero or an error / nan?
The first result is when i is 1, so it simplifies to:
math.sin(2 * math.pi) / math.sin(math.pi)
Due to floating point errors, math.sin(2 * math.pi) evaluates to -2.44921270764e-16, while math.sin(math.pi) evaluates to 1.22460635382e-16.
A floating point division of -2.44921270764e-16 / 1.22460635382e-16 gives -2.0, so that's the final output.
In the absence of floating point errors, both math.sin(2 * math.pi) and math.sin(math.pi) should have evaluated to zero, but it just so happened by the combined quirks of the floating point implementation and Python sin function implementation that the floating point error of the first was twice that of the second, and negative, so dividing them gave -2.
The floating point error in the internal representation of math.pi * 2 is twice that of math.pi because when you double a value with an error margin the error margin also doubles, and it is not possible to represent pi as a floating point number without some error. Speculation: that error propagates through the sin calculation, and a negative is introduced because of something in the sin calculation related to the fact that the sin function in the range of pi to 2 pi is the negative of the function in the range of 0 to pi.
If you want to round extremely small values to zero, you can use numpy.around to round to a given number of decimals, e.g:
import numpy
for i in range(1, 11):
print numpy.around(numpy.sin(2 * numpy.pi / i), 15) / numpy.around(numpy.sin(numpy.pi / i), 15)
This produces a nan for the first result.
These errors are from simple floating point arithmetics... that's just the way this works. So, you can avoid using floating point, but that gives you a lot of pain probably.
If you look at how floating point works here, you'll see that errors will happen... a lot. That's basically the reason why most databases support fixed-point precision for money calculations. That said, sin/cos on fixed point is going to be a pain...
One simple way to avoid these errors is to use a simple pre-calculated lookup table for all (or some of the) 180' angles of sin/cos.
Please forgive me, but I only really know how to somewhat code in VB, and python is not what I'm used to. I did try to see if other people have made and or shown an algorithm that I'm trying to accomplish.
I have a visualizer design in my head and What I have been trying to do is get a number of cubes (variable input for now) to be placed a certain distance (maybe 5-10 blender units) from the center of the scene and angle the faces so that there will be one face pointing to the center and one face pointing the opposite direction. I'm trying to just start with 10 cubes because I feel like it will be a fair number to hopefully show a circle shape.
I made an image to help describe what I am trying to do:
All I have been able to figure out so far is that I need to add a cube with a certain rotation, and that rotation needs to be stepped for each cube. so a small equation is needed, something like this.
(10) (36)
360 / numberOfCubes = steppedAngle
That's all I have been able to figure out because I don't know how to program python to do such.
Any help is greatly appreciated, and will be credited in the final render.
Update: 1
Thanks to the help from the answer below, I finally got it to work how i wanted.
img http://vvcap.net/db/bKKUz3Uw4WUqL_WVDU0j.png
and here is the code written in help from the answer below.
'
import bpy
import math
##num of cubes
n = 10
##distange from center
radius = 7
for i in range(1, n + 1):
angle = (i - 1) * math.pi * 2 / n
xcoord=(radius * math.cos(angle))
ycoord=(radius * math.sin(angle))
bpy.ops.mesh.primitive_cube_add(location=(xcoord,ycoord,0),rotation=(0,0,angle))
'
Let's start with cubes in a circle, and we will work our way from there.
You have N cubes, and you want to place them in a circle of radius R around the center of the universe (0,0,0).
Applying basic trigonometry:
Each cube is on one of the radius of the circle, when you divide the circle by N. Therefore, your first cube is at 0 rad, your second cube is at 2*pi/N rad, your third cube is at 2 * 360/N rad, ... your N cube is at (N-1) * 2*pi/N rad. Now we have a formula:
Location of the cube in the circle = (i - 1) * 2*pi/N in radians, for each i from 1 to N.
Now, the location in space coordinates is (r*cos(angle), r*sin(angle), 0) for a circle that is placed on the XY plane and it's center is on (0,0,0).
My Blender Python is very rusty, so I won't provide you a complete solution, but it should be this way:
import math
for i in range(1, N + 1):
angle = (i - 1) * math.pi * 2 / N
x_coord = radius * math.cos(angle)
y_coord = radius * math.sin(angle)
z_coord = 0
cube = place_cube(x_coord, y_coord, z_coord)
This will place the cubes on the right coordinates, but it won't turn them the right way. Fortunately, you can rotate each cube by angle, and get it in the right orientation. So you can do:
import math
for i in range(1, N + 1):
angle = (i - 1) * math.pi * 2 / N
x_coord = radius * math.cos(angle)
y_coord = radius * math.sin(angle)
z_coord = 0
cube = place_cube(x_coord, y_coord, z_coord)
cube.rotate_around_z(angle)
I have not provided the place_cube and rotate_around_z functions because I hardly remember the Blender Python api, but it shouldn't be too hard.
I read this question and implemented the accepted answer in Python (see below). It works in principle, but the results are consistently about 30% higher than expected (Czech Republic) - is that the expected accuracy of this algorithm?
To verify the algorithm, I used BoundingBox to get a bounding box with a known diagonal distance (building, two cities) and used the output coordinates as input for "my" algorithm.
Where is the problem?
my implementation?
the algorithm itself?
Python?
testing?
My implementation:
R= 6371 #km
dLat = math.radians(lat2-lat1)
dLon = math.radians(lon2-lon1)
lat1 = math.radians(lat1)
lat2 = math.radians(lat2)
a= math.sin(dLat/2)*math.sin(dLat/2) + math.sin(dLon/2) * math.sin(dLon/2) * math.cos(lat1) * math.cos(lat2)
c= 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))
d = R * c;
return d
No, the algorithm is not supposed to have an error of that magnitude. The link specifies that you can expect around a 0.3% error.
I can not reproduce your results with your code, so I believe the error is with your testing.
Here's some testing data from a site with the distance between and coordinates of Prague and Brno in decimal degrees format:
lat_prague, long_prague = 50.0833, 14.4667
lat_brno, long_brno = 49.2000, 16.6333
expected_km = 184.21
Here are the testing results:
>>> def calc(lat1,lon1, lat2,lon2):
# ... your code ...
>>> calc(lat_prague,long_prague,lat_brno,long_brno)
184.34019283649852
>>> calc(lat_prague,long_prague,lat_brno,long_brno) / expected_km
1.0007067631317437
A wild guess: for locations in the Czech Republic, the error you're getting seems in the right order of magnitude for with mixing up latitude and longitude:
>>> calc(long_prague,lat_prague,long_brno,lat_brno)
258.8286271447481
>>> calc(long_prague,lat_prague,long_brno,lat_brno) / expected_km
1.405073704710646
This is apparently a known confusion. A coordinate specified as only a pair of numbers is ambiguous (for instance: both BoundingBox and the reference for the distance above use (long, lat), and the algorithm uses the ordering lat, long). When you come across the ambiguous format with an unfamiliar data source without a formal specification, you'll just have to sanity-check. Sites like Wikipedia will tell you unambiguously that Prague lies at "50°05′N 14°25′E" -- that is, very roughly, around 50 degrees latitude (north-south) and 14 degrees longitude (east-west).