Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dwilliamson/9953484 to your computer and use it in GitHub Desktop.
Save dwilliamson/9953484 to your computer and use it in GitHub Desktop.
#
# Correcting Art of Assembly's flawed acos implementation in Chapter 14
# http://flint.cs.yale.edu/cs422/doc/art-of-asm/pdf/CH14.PDF
#
import math
# Alias commonly used math functions
sqrt = math.sqrt
atan = math.atan
atan2 = math.atan2
#
# From Art of Assembly, Chapter 14
# States allowable range is -1 <= x <= 1
# Does not work for x < 0
#
def acos_ArtOfASM(x):
return atan(sqrt((1 - x * x) / (x * x)))
#
# From Mathworld, correctly states range is x >= 0 (with x=0 caveat)
# http://mathworld.wolfram.com/InverseCosine.html
#
def acos_Mathworld(x):
return atan(sqrt((1 - x * x) / x))
#
# Use atan2 to cater for x <= 0 by taking quadrant shift into account:
#
# atan2(y, x) = ...
# atan(y / x) x > 0
# atan(y / x) + pi y >= 0, x < 0
# atan(y / x) - pi y < 0, x < 0
# pi / 2 y > 0, x = 0
# -pi / 2 y < 0, x = 0
#
def acos_MathworldQuadrant(x):
return atan2(sqrt(1 - x * x), x)
print acos_ArtOfASM(1)
print acos_ArtOfASM(-1)
print acos_Mathworld(1)
print acos_Mathworld(-1)
print acos_MathworldQuadrant(1)
print acos_MathworldQuadrant(-1)
#
# This results in a more correct implementation with the input range -1 <= x <= 1
# 1 less instruction and fdiv swapped for a fxch instruction
#
__asm
{
fld st(0) // [x]
fld st(0) // [x] [x]
fmul // [x * x] [x]
fld1 // [1] [x * x] [x]
fsubr // [1 - x * x] [x]
fsqrt // [sqrt(1 - x * x)] [x]
fxch st(1) // [x] [sqrt(1 - x * x)]
fpatan // [acos]
ret
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment