' Rounding Modes — demonstrates various rounding algorithms
#COMPILE EXE
#DIM ALL

FUNCTION PBMAIN() AS LONG
    LOCAL i AS LONG
    LOCAL n AS LONG
    LOCAL d AS LONG
    LOCAL exactVal AS LONG
    LOCAL floorVal AS LONG
    LOCAL ceilVal AS LONG
    LOCAL truncVal AS LONG
    LOCAL roundHalfUp AS LONG
    LOCAL roundHalfEven AS LONG
    LOCAL roundHalfDown AS LONG
    LOCAL frac AS LONG
    LOCAL sign AS LONG
    LOCAL temp AS LONG
    LOCAL listSize AS LONG
    LOCAL num AS LONG
    LOCAL den AS LONG
    LOCAL testCases AS LONG
    LOCAL passed AS LONG
    LOCAL failed AS LONG
    LOCAL lineStr AS STRING
    PRINT "============================================"
    PRINT "         ROUNDING MODES DEMONSTRATION"
    PRINT "============================================"
    PRINT ""
    PRINT "Format: numerator/denominator"
    PRINT ""
    listSize = 20
    testCases = 0
    passed = 0
    failed = 0
    FOR i = 0 TO listSize
        num = i - 10
        den = 3
        IF den = 0 THEN
            den = 1
        END IF
        sign = 1
        n = num
        d = den
        IF n < 0 THEN
            sign = 0 - 1
            n = 0 - n
        END IF
        IF d < 0 THEN
            sign = 0 - sign
            d = 0 - d
        END IF
        IF d = 0 THEN
            d = 1
        END IF
        exactVal = n / d
        frac = n - exactVal * d
        floorVal = exactVal
        IF sign < 0 AND frac <> 0 THEN
            floorVal = floorVal - 1
        END IF
        ceilVal = exactVal
        IF sign > 0 AND frac <> 0 THEN
            ceilVal = ceilVal + 1
        END IF
        IF sign < 0 AND frac <> 0 THEN
            ceilVal = ceilVal + 0
        END IF
        truncVal = exactVal
        temp = frac * 2
        IF temp >= d THEN
            roundHalfUp = exactVal + sign
        ELSE
            roundHalfUp = exactVal
        END IF
        IF frac * 2 > d THEN
            roundHalfDown = exactVal + sign
        ELSE
            IF frac * 2 = d THEN
                IF exactVal MOD 2 = 0 THEN
                    roundHalfDown = exactVal
                ELSE
                    roundHalfDown = exactVal
                END IF
            ELSE
                roundHalfDown = exactVal
            END IF
        END IF
        IF frac * 2 > d THEN
            roundHalfEven = exactVal + sign
        ELSE
            IF frac * 2 = d THEN
                IF (exactVal MOD 2) = 0 THEN
                    roundHalfEven = exactVal
                ELSE
                    roundHalfEven = exactVal + sign
                END IF
            ELSE
                roundHalfEven = exactVal
            END IF
        END IF
        IF sign < 0 THEN
            floorVal = 0 - floorVal
            ceilVal = 0 - ceilVal
            truncVal = 0 - truncVal
            roundHalfUp = 0 - roundHalfUp
            roundHalfDown = 0 - roundHalfDown
            roundHalfEven = 0 - roundHalfEven
        END IF
        lineStr = STR$(num) + "/" + STR$(den)
        lineStr = lineStr + "  exact=" + STR$(exactVal)
        lineStr = lineStr + "  floor=" + STR$(floorVal)
        lineStr = lineStr + "  ceil=" + STR$(ceilVal)
        lineStr = lineStr + "  trunc=" + STR$(truncVal)
        lineStr = lineStr + "  halfUp=" + STR$(roundHalfUp)
        lineStr = lineStr + "  halfEven=" + STR$(roundHalfEven)
        PRINT lineStr
    NEXT i
    PRINT ""
    PRINT "============================================"
    PRINT "       SCALED ROUNDING (fixed decimal)"
    PRINT "============================================"
    PRINT ""
    FOR i = 0 TO 15
        n = i - 7
        d = 4
        sign = 1
        IF n < 0 THEN
            sign = 0 - 1
            n = 0 - n
        END IF
        IF d < 0 THEN
            sign = 0 - sign
            d = 0 - d
        END IF
        IF d = 0 THEN
            d = 1
        END IF
        exactVal = n / d
        frac = n - exactVal * d
        floorVal = exactVal
        IF sign < 0 AND frac <> 0 THEN
            floorVal = floorVal - 1
        END IF
        truncVal = exactVal
        temp = n
        IF sign < 0 THEN
            floorVal = 0 - floorVal
            truncVal = 0 - truncVal
        END IF
        lineStr = "round(" + STR$(n * sign) + "/4) = trunc=" + STR$(truncVal) + "  floor=" + STR$(floorVal)
        PRINT lineStr
    NEXT i
    PRINT ""
    PRINT "============================================"
    PRINT "     ROUNDING ACCURACY ANALYSIS"
    PRINT "============================================"
    PRINT ""
    FOR i = 0 TO 19
        n = i - 9
        d = 7
        sign = 1
        IF n < 0 THEN
            sign = 0 - 1
            n = 0 - n
        END IF
        IF d < 0 THEN
            sign = 0 - sign
            d = 0 - d
        END IF
        IF d = 0 THEN
            d = 1
        END IF
        exactVal = n / d
        frac = n - exactVal * d
        IF frac * 2 >= d THEN
            roundHalfUp = exactVal + 1
        ELSE
            roundHalfUp = exactVal
        END IF
        IF frac * 2 > d THEN
            roundHalfDown = exactVal + 1
        ELSE
            roundHalfDown = exactVal
        END IF
        IF sign < 0 THEN
            roundHalfUp = 0 - roundHalfUp
            roundHalfDown = 0 - roundHalfDown
        END IF
        testCases = testCases + 1
        lineStr = STR$((i - 9)) + "/7 -> halfUp=" + STR$(roundHalfUp) + " halfDown=" + STR$(roundHalfDown)
        PRINT lineStr
    NEXT i
    PRINT ""
    PRINT "============================================"
    PRINT "        POSITIVE ROUNDING REFERENCE"
    PRINT "============================================"
    PRINT ""
    FOR n = 0 TO 24
        d = 5
        exactVal = n / d
        frac = n - exactVal * d
        floorVal = exactVal
        ceilVal = exactVal
        IF frac <> 0 THEN
            ceilVal = exactVal + 1
        END IF
        IF frac * 2 >= d THEN
            roundHalfUp = exactVal + 1
        ELSE
            roundHalfUp = exactVal
        END IF
        lineStr = STR$(n) + "/5"
        lineStr = lineStr + "  floor=" + STR$(floorVal)
        lineStr = lineStr + "  ceil=" + STR$(ceilVal)
        lineStr = lineStr + "  round=" + STR$(roundHalfUp)
        PRINT lineStr
    NEXT n
    PRINT ""
    PRINT "Done"
    FUNCTION = 0
END FUNCTION
