#!/usr/bin/awk -f
#
# Copyright (c) 2009 Ariff Abdullah <ariff@FreeBSD.org>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# $FreeBSD$
#
# Date: Tue Aug  4 15:18:44 MYT 2009
#   OS: FreeBSD miki.MyBSD.org.my 8.0-BETA2 i386
#

#
# Some basic Math functions.
#
function abs(x)
{
        return (((x < 0) ? -x : x) + 0);
}

function fabs(x)
{
        return (((x < 0.0) ? -x : x) + 0.0);
}

function floor(x, r)
{
        r = int(x);
        if (r > x)
                r--;
        return (r + 0);
}

#
# What the hell...
#
function shl(x, y)
{
        while (y > 0) {
                x *= 2;
                y--;
        }
        return (x);
}

function fx(v, x, r)
{
        x = floor(((2.0 * v) * Z_OPTX_ONE) + 0.5);

        if (Z_OPTX_SHIFT > 30) {
                r = sprintf("%sLL", x);
        } else {
                if (abs(x) != x)
                        r = sprintf("-0x%08xLL", abs(x));
                else
                        r = sprintf("0x%08xLL", abs(x));
        }

        return (r);
}

function dump_optx(optx)
{
        printf("#elif defined(Z_COEFF_INTERP_OPT%dX)\n", optx["name"]);
        printf("\tint32_t zoz, zoe1, zoe2, zoe3, zoo1, zoo2, zoo3;\n");
        printf("\tint32_t zoc0, zoc1, zoc2, zoc3, zoc4, zoc5;\n\n");

        printf("\t/* 6-point, 5th-order Optimal %dx */\n", optx["name"]);
        printf("\tzoz = z - (Z_ONE >> 1);\n");
        printf("\tzoe1 = z_coeff[1] + z_coeff[0];\n");
        printf("\tzoe2 = z_coeff[2] + z_coeff[-1];\n");
        printf("\tzoe3 = z_coeff[3] + z_coeff[-2];\n");
        printf("\tzoo1 = z_coeff[1] - z_coeff[0];\n");
        printf("\tzoo2 = z_coeff[2] - z_coeff[-1];\n");
        printf("\tzoo3 = z_coeff[3] - z_coeff[-2];\n\n");

        printf("\tzoc0 = %s((%s * zoe1) + (%s * zoe2) +\n\t"           \
            "    (%s * zoe3), %d);\n",                                 \
            Z_RSHIFT,                                                  \
            fx(optx[0, 0]), fx(optx[0, 1]), fx(optx[0, 2]), Z_OPTX_SHIFT);
        printf("\tzoc1 = %s((%s * zoo1) + (%s * zoo2) +\n\t"           \
            "    (%s * zoo3), %d);\n",                                 \
            Z_RSHIFT,                                                  \
            fx(optx[1, 0]), fx(optx[1, 1]), fx(optx[1, 2]), Z_OPTX_SHIFT);
        printf("\tzoc2 = %s((%s * zoe1) + (%s * zoe2) +\n\t"           \
            "    (%s * zoe3), %d);\n",                                 \
            Z_RSHIFT,                                                  \
            fx(optx[2, 0]), fx(optx[2, 1]), fx(optx[2, 2]), Z_OPTX_SHIFT);
        printf("\tzoc3 = %s((%s * zoo1) + (%s * zoo2) +\n\t"           \
            "    (%s * zoo3), %d);\n",                                 \
            Z_RSHIFT,                                                  \
            fx(optx[3, 0]), fx(optx[3, 1]), fx(optx[3, 2]), Z_OPTX_SHIFT);
        printf("\tzoc4 = %s((%s * zoe1) + (%s * zoe2) +\n\t"           \
            "    (%s * zoe3), %d);\n",                                 \
            Z_RSHIFT,                                                  \
            fx(optx[4, 0]), fx(optx[4, 1]), fx(optx[4, 2]), Z_OPTX_SHIFT);
        printf("\tzoc5 = %s((%s * zoo1) + (%s * zoo2) +\n\t"           \
            "    (%s * zoo3), %d);\n\n",                               \
            Z_RSHIFT,                                                  \
            fx(optx[5, 0]), fx(optx[5, 1]), fx(optx[5, 2]), Z_OPTX_SHIFT);

        printf("\tcoeff = "                                            \
            "Z_RSHIFT(Z_RSHIFT((Z_RSHIFT((Z_RSHIFT((Z_RSHIFT((Z_RSHIFT(\n"     \
            "\t    (int64_t)zoc5 * zoz, Z_SHIFT) +\n"                  \
            "\t    zoc4) * zoz, Z_SHIFT) + zoc3) * zoz, Z_SHIFT) +\n"  \
            "\t    zoc2) * zoz, Z_SHIFT) + zoc1) * zoz, Z_SHIFT) + "   \
            "zoc0, 1);\n");
}

BEGIN {
        Z_OPTX_SHIFT = 30;
        Z_OPTX_ONE   = shl(1, Z_OPTX_SHIFT);
        Z_RSHIFT     = (Z_OPTX_SHIFT > 30) ? "Z_RSHIFT_L" : "Z_RSHIFT"

        opt32x["name"] = 32;
        opt32x[0, 0] = 0.42685983409379380;
        opt32x[0, 1] = 0.07238123511170030;
        opt32x[0, 2] = 0.00075893079450573;
        opt32x[1, 0] = 0.35831772348893259;
        opt32x[1, 1] = 0.20451644554758297;
        opt32x[1, 2] = 0.00562658797241955;
        opt32x[2, 0] = -0.21700917722129243;
        opt32x[2, 1] = 0.20051376594086157;
        opt32x[2, 2] = 0.01649541128040211;
        opt32x[3, 0] = -0.25112715343740988;
        opt32x[3, 1] = 0.04223025992200458;
        opt32x[3, 2] = 0.02488727472995134;
        opt32x[4, 0] = 0.04166946673533273;
        opt32x[4, 1] = -0.06250420114356986;
        opt32x[4, 2] = 0.02083473440841799;
        opt32x[5, 0] = 0.08349799235675044;
        opt32x[5, 1] = -0.04174912841630993;
        opt32x[5, 2] = 0.00834987866042734;

        opt16x["name"] = 16;
        opt16x[0, 0] = 0.41809989254549901;
        opt16x[0, 1] = 0.08049339946273310;
        opt16x[0, 2] = 0.00140670799165932;
        opt16x[1, 0] = 0.32767596257424964;
        opt16x[1, 1] = 0.20978189376640677;
        opt16x[1, 2] = 0.00859567104974701;
        opt16x[2, 0] = -0.20694461811296000;
        opt16x[2, 1] = 0.18541689550861262;
        opt16x[2, 2] = 0.02152772260740132;
        opt16x[3, 0] = -0.21686095413034051;
        opt16x[3, 1] = 0.02509557922091643;
        opt16x[3, 2] = 0.02831484751363800;
        opt16x[4, 0] = 0.04163046817137675;
        opt16x[4, 1] = -0.06244556931623735;
        opt16x[4, 2] = 0.02081510113314315;
        opt16x[5, 0] = 0.07990500783668089;
        opt16x[5, 1] = -0.03994519162531633;
        opt16x[5, 2] = 0.00798609327859495;

        opt8x["name"] = 8;
        opt8x[0, 0] = 0.41660797292569773;
        opt8x[0, 1] = 0.08188468587188069;
        opt8x[0, 2] = 0.00150734119050266;
        opt8x[1, 0] = 0.32232780822726981;
        opt8x[1, 1] = 0.21076321997422021;
        opt8x[1, 2] = 0.00907649978070957;
        opt8x[2, 0] = -0.20521999396147150;
        opt8x[2, 1] = 0.18282942057327367;
        opt8x[2, 2] = 0.02239057377093268;
        opt8x[3, 0] = -0.21022298520246224;
        opt8x[3, 1] = 0.02176417471349534;
        opt8x[3, 2] = 0.02898626924395209;
        opt8x[4, 0] = 0.04149963966704384;
        opt8x[4, 1] = -0.06224707096203808;
        opt8x[4, 2] = 0.02074742969707599;
        opt8x[5, 0] = 0.07517133281176167;
        opt8x[5, 1] = -0.03751837438141215;
        opt8x[5, 2] = 0.00747588873055296;

        opt4x["name"] = 4;
        opt4x[0, 0] = 0.41496902959240894;
        opt4x[0, 1] = 0.08343081932889224;
        opt4x[0, 2] = 0.00160015038681571;
        opt4x[1, 0] = 0.31625515004859783;
        opt4x[1, 1] = 0.21197848565176958;
        opt4x[1, 2] = 0.00956166668408054;
        opt4x[2, 0] = -0.20327189654887537;
        opt4x[2, 1] = 0.17989908432249280;
        opt4x[2, 2] = 0.02337283412161328;
        opt4x[3, 0] = -0.20209241069835732;
        opt4x[3, 1] = 0.01760734419526000;
        opt4x[3, 2] = 0.02985927012435252;
        opt4x[4, 0] = 0.04100948858761910;
        opt4x[4, 1] = -0.06147760875085254;
        opt4x[4, 2] = 0.02046802954581191;
        opt4x[5, 0] = 0.06607747864416924;
        opt4x[5, 1] = -0.03255079211953620;
        opt4x[5, 2] = 0.00628989632244913;

        opt2x["name"] = 2;
        opt2x[0, 0] = 0.40513396007145713;
        opt2x[0, 1] = 0.09251794438424393;
        opt2x[0, 2] = 0.00234806603570670;
        opt2x[1, 0] = 0.28342806338906690;
        opt2x[1, 1] = 0.21703277024054901;
        opt2x[1, 2] = 0.01309294748731515;
        opt2x[2, 0] = -0.19133768254035194;
        opt2x[2, 1] = 0.16187844487943592;
        opt2x[2, 2] = 0.02946017143111912;
        opt2x[3, 0] = -0.16471626190554542;
        opt2x[3, 1] = -0.00154547203542499;
        opt2x[3, 2] = 0.03399271444851909;
        opt2x[4, 0] = 0.03845798729588149;
        opt2x[4, 1] = -0.05712936104242644;
        opt2x[4, 2] = 0.01866750929921070;
        opt2x[5, 0] = 0.04317950185225609;
        opt2x[5, 1] = -0.01802814255926417;
        opt2x[5, 2] = 0.00152170021558204;

        dump_optx(opt32x);
        dump_optx(opt16x);
        dump_optx(opt8x);
        dump_optx(opt4x);
        dump_optx(opt2x);
}