/*
 * Copyright (c) 2024-2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

export class MathCordic  {
    static readonly AG_CONST : double = 0.6072529350;
    static readonly TARGET_ANGLE : double = 28.027;
    static readonly expected : double = 10362.570468755888;
    static readonly ANGLES : double[] = [MathCordic.fnFixed(45.0), MathCordic.fnFixed(26.565), MathCordic.fnFixed(14.0362), MathCordic.fnFixed(7.12502), MathCordic.fnFixed(3.57633), MathCordic.fnFixed(1.78991), MathCordic.fnFixed(0.895174), MathCordic.fnFixed(0.447614), MathCordic.fnFixed(0.223811), MathCordic.fnFixed(0.111906), MathCordic.fnFixed(0.055953), MathCordic.fnFixed(0.027977)];

    static fnFixed(x : double): double {
        return x * 65536.0;
    }

    static fnFloat(x : double): double {
        return x / 65536.0;
    }

    static fnDegToRad(x : double): double {
        return 0.017453 * x;
    }

    static cordicsincos(target : double): double {
        let x : double;
        let y : double;
        let targetAngle : double = MathCordic.fnFixed(target);
        let currAngle : double = 0;
        let step : int ;
        x = MathCordic.fnFixed(MathCordic.AG_CONST * cos(0));
        y = sin(0);
        for (step = 0; step < 12; step++) {
            let newX : double ;
            if (targetAngle > currAngle) {
                newX = x - (y.toInt() >> step);
                y = (x.toInt() >> step) + y;
                x = newX;
                currAngle += MathCordic.ANGLES[step];
            }
            else {
                newX = x + (y.toInt() >> step);
                y = -(x.toInt() >> step) + y;
                x = newX;
                currAngle -= MathCordic.ANGLES[step];
            }
        }
        return MathCordic.fnFloat(x) * MathCordic.fnFloat(y);
    }

    static cordic(runs : int): double {
        let total : double = 0;
        for (let i : int = 0; i < runs; i++) {
            total += MathCordic.cordicsincos(MathCordic.TARGET_ANGLE);
        }
        return total;
    }

    n : int;

    public  run(): void {
        this.n = 25000;
        let total : double = MathCordic.cordic(this.n);

        arktest.assertEQ(total, MathCordic.expected,  "Incorrect result");
    }
}

function main(): void {
  let a = new MathCordic;
  a.run();
}