Hyperbolic CORDIC in rotation (Z -> 0) to calculate sinh and cosh?

148 views Asked by At

I implemented both circular and hyperbolic CORDIC algorithm in rotation mode:Z -> 0

In case of sin and cos which using circular implementation, the results are accurate. In case of sinh and cosh which is the hyperbolic algorithm, they are not.

The output of the code below (*_calc is the CORDIC version, *_good is the math.* version) is the following:

sin_good(20): 0.3420201433256687
sin_calc(20): 0.34202014332566866

sinh_good(20): 242582597.70489514
sinh_calc(20): 0.3555015499407712

cos_good(20): 0.9396926207859084
cos_calc(20): 0.9396926207859082

cosh_good(20): 242582597.70489514
cosh_calc(20): 1.0594692478629741

What am I doing wrong?

    def lookup_circular(iteration):
        return math.degrees(math.atan(2 ** -iteration))

    def lookup_linear(iteration):
        return 2 ** -iteration

    def lookup_hyperbolic(iteration):
        return math.degrees(math.atanh(2 ** -iteration))

    def sin(angle):
        x, y, z = cordic_circular_rotation_zto0(
            x=1 / circular_scaling_factor(),
            y=0,
            z=float(angle)
        )

        return y

    def cos(angle):
        x, y, z = cordic_circular_rotation_zto0(
            x=1 / circular_scaling_factor(),
            y=0,
            z=float(angle)
        )

        return x

    def sinh(angle):
        x, y, z = cordic_hyperbolic_rotation_zto0(
            x=1 / hyperbolic_scaling_factor(),
            y=0,
            z=angle
        )

        return y

    def cosh(angle):
        x, y, z = cordic_hyperbolic_rotation_zto0(
            x=1 / hyperbolic_scaling_factor(),
            y=0,
            z=angle
        )

        return x

    def cordic_circular_rotation_zto0(x, y, z, n=64):
        i = 0

        while i <= n:
            if z < 0:
                newx = x + (y * 2.0 ** (-i))
                newy = y - (x * 2.0 ** (-i))
                z = z + lookup_circular(i)
            else:
                newx = x - (y * 2.0 ** (-i))
                newy = y + (x * 2.0 ** (-i))
                z = z - lookup_circular(i)

            x = newx
            y = newy
            i += 1

        return x, y, z

    def cordic_hyperbolic_rotation_zto0(x, y, z, n=64):
        i = 1
        repeat = 4

        while i <= n:
            if z < 0:
                newx = x - (y * 2.0 ** (-i))
                newy = y - (x * 2.0 ** (-i))
                z = z + lookup_hyperbolic(i)
            else:
                newx = x + (y * 2.0 ** (-i))
                newy = y + (x * 2.0 ** (-i))
                z = z - lookup_hyperbolic(i)

            x = newx
            y = newy

            if i == repeat:
                repeat = (i * 3) + 1
            else:
                i += 1

        return x, y, z

    def circular_scaling_factor(n=64):
        e = 1

        for i in range(0, n):
            e = e * math.sqrt(1 + 2 ** (-2 * i))

        return e

    def hyperbolic_scaling_factor(n=64):
        e = 1

        for i in range(1, n):
            e = e * math.sqrt(1 - 2 ** (-2 * i))

        return e

    if __name__ == '__main__':
        angle = 20

        sin_res = sin(angle)
        print("sin_good({}): {}".format(angle, math.sin(math.radians(angle))))
        print("sin_calc({}): {}".format(angle, sin_res))

        print()
    
        sinh_res = sinh(angle)
        print("sinh_good({}): {}".format(angle, math.sinh(angle)))
        print("sinh_calc({}): {}".format(angle, sinh_res))
    
        print()

        cos_res = cos(angle)
        print("cos_good({}): {}".format(angle, math.cos(math.radians(angle))))
        print("cos_calc({}): {}".format(angle, cos_res))
    
        print()

        cosh_res = cosh(angle)
        print("cosh_good({}): {}".format(angle, math.cosh(angle)))
        print("cosh_calc({}): {}".format(angle, cosh_res))
1

There are 1 answers

0
XaC On

By removing the math.degrees of the inverse hyperbolic tan of lookup_hyperbolic, I find the following result for cosh:

both functions match until x~1.1, and then the cordic function stays constant. enter image description here

Which is what can be found in Digital Arithmetic - Ercegovac/Lang 2003 chapter 11

max angle = 1.11817

Same for sinh:

enter image description here

There is an extended cordic alogrithm that you could try to implement:

Expanding the Range of Convergence of the CORDIC Algorithm X. Hu, R. Harber, S. Bass Published 1991 Computer Science IEEE Trans. Computers