Don't make me REPETEND myself...
#1
So Jack got me working on string math again. I don't know whether to thank him or shoot him (refers to avatar) but, here we go again...

I was thinking if I ever want to address using repetends (repeating decimals) to make even simple string equations like 1 / 3 * 3 = 1, instead of .999... then I might need to explore how to identify those repeating decimal occurrences.

Below is a sample program (non idiot-proof so don't post it accepted invalid data) that I hope detects all instances of repetends. I coded the first part, and then added (pasted) in the division routine from my string math program.

Try inputting 1 as the numerator and 97 as the denominator and you will largest repetend I know of, 96 digits befor the sequence repeats!

Code: (Select All)
WIDTH 170, 42
_SCREENMOVE 0, 0
DO
    DIM SHARED runningtotal$, limit&&
    limit&& = 200

    LINE INPUT "Numerator: "; a$
    LINE INPUT "Denominator: "; b$

    calcdiv a$, b$

    COLOR 14, 0: PRINT runningtotal$; "  ";: COLOR 7, 0

    IF INSTR(runningtotal$, ".") THEN
        x$ = MID$(runningtotal$, INSTR(runningtotal$, ".") + 1)
        x$ = MID$(x$, LEN(b$) - LEN(a$) + 2)
        FOR i = 1 TO LEN(x$)
            k = j
            j = INSTR(i + 1, x$, MID$(x$, 1, i))
            IF j = k THEN EXIT FOR
        NEXT

        SELECT CASE j
            CASE 0
                IF MID$(x$, 1, 2) <> MID$(x$, 2, 2) OR LEN(x$) < 2 THEN
                    msg$ = "Non-repetend."
                ELSE
                    IF MID$(runningtotal$, INSTR(runningtotal$, ".") + 1, 1) <> MID$(x$, 1, 1) THEN
                        msg$ = "Eventual infinite repetend."
                    ELSE
                        msg$ = "Repetend infinite."
                    END IF
                END IF
            CASE ELSE
                msg$ = "Repetend length: " + LTRIM$(STR$(j - 1))
        END SELECT
    ELSE
        msg$ = "Non-decimal"
    END IF
    PRINT msg$
    CLEAR
    PRINT
LOOP

SUB calcdiv (a$, b$)
    stringmatha$ = a$
    stringmathb$ = b$

    operationdivision% = -1
    divbuffer& = LEN(stringmathb$) - LEN(stringmatha$)
    IF divbuffer& < 0 THEN divbuffer& = 0
    d2dividend$ = stringmatha$
    d1divisor$ = stringmathb$
    IF LEFT$(d1divisor$, 1) = "0" AND LEN(d1divisor$) = 1 THEN PRINT "Division by zero not allowed.": EXIT SUB
    IF LEFT$(d1divisor$, 1) = "-" THEN divsign% = -1: d1divisor$ = MID$(d1divisor$, 2)
    IF LEFT$(d2dividend$, 1) = "-" THEN
        IF divsign% THEN
            divsign% = 0
        ELSE
            divsign% = -1
        END IF
        d2dividend$ = MID$(d2dividend$, 2)
    END IF
    IF INSTR(d1divisor$, ".") <> 0 THEN
        DO UNTIL RIGHT$(d1divisor$, 1) <> "0"
            d1divisor$ = MID$(d1divisor$, 1, LEN(d1divisor$) - 1) ' Strip off trailing zeros
        LOOP
        divplace& = LEN(d1divisor$) - INSTR(d1divisor$, ".")
        d1divisor$ = MID$(d1divisor$, 1, INSTR(d1divisor$, ".") - 1) + MID$(d1divisor$, INSTR(d1divisor$, ".") + 1) ' Strip off decimal point.
        DO UNTIL LEFT$(d1divisor$, 1) <> "0"
            d1divisor$ = MID$(d1divisor$, 2) ' Strip off leading zeros for divisors smaller than .1
        LOOP
    END IF

    IF INSTR(d2dividend$, ".") <> 0 THEN
        d2dividend$ = d2dividend$ + STRING$(divplace& - LEN(d2dividend$) - INSTR(d2dividend$, "."), "0") ' Add any zeros based on the length of dividend at decimal - length of divisor at decimal. If less than zero, nothing added.
        divplace2& = INSTR(d2dividend$, ".")
        DO UNTIL RIGHT$(d2dividend$, 1) <> "0"
            d2dividend$ = MID$(d2dividend$, 1, LEN(d2dividend$) - 1) ' Strip off trailing zeros
        LOOP
        d2dividend$ = MID$(d2dividend$, 1, INSTR(d2dividend$, ".") - 1) + MID$(d2dividend$, INSTR(d2dividend$, ".") + 1) ' Strip off decimal point.
    ELSE
        d2dividend$ = d2dividend$ + STRING$(divplace&, "0") ' Add any zeros based on the length of dividend at decimal - length of divisor at decimal. If less than zero, nothing added.
        divplace& = 0
    END IF
    DO
        DO
            divremainder& = divremainder& + 1: divremainder$ = divremainder$ + MID$(d2dividend$, divremainder&, 1)
            IF MID$(d2dividend$, divremainder&, 1) = "" THEN
                IF divremainder$ = STRING$(LEN(divremainder$), "0") AND LEN(quotient$) > LEN(d2dividend$) THEN divflag% = -1: EXIT DO
                divcarry& = divcarry& + 1
                IF divcarry& = 1 THEN divplace3& = divremainder& - 1
                IF divcarry& > limit&& + 1 + divbuffer& THEN
                    divflag% = -2: EXIT DO
                END IF
                divremainder$ = divremainder$ + "0" ' No more digits to bring down.
            END IF
            IF LEN(divremainder$) > LEN(d1divisor$) OR LEN(divremainder$) = LEN(d1divisor$) AND divremainder$ >= d1divisor$ THEN EXIT DO
            quotient$ = quotient$ + "0"
        LOOP
        IF divflag% THEN divflag% = 0: EXIT DO
        FOR div_i% = 9 TO 1 STEP -1
            stringmatha$ = LTRIM$(STR$(div_i%)): stringmathb$ = d1divisor$
            m_product$ = "": GOSUB string_multiply
            tempcutd$ = divremainder$ ' divremainder$ can be 00 or other leading zero values.
            DO
                IF LEN(tempcutd$) = 1 THEN EXIT DO
                IF LEFT$(tempcutd$, 1) = "0" THEN
                    tempcutd$ = MID$(tempcutd$, 2)
                ELSE
                    EXIT DO
                END IF
            LOOP
            IF LEN(tempcutd$) > LEN(m_product$) OR LEN(tempcutd$) = LEN(m_product$) AND m_product$ <= tempcutd$ THEN EXIT FOR
        NEXT
        quotient$ = quotient$ + LTRIM$(STR$(div_i%))
        stringmatha$ = LTRIM$(STR$(div_i%)): stringmathb$ = d1divisor$
        m_product$ = "": GOSUB string_multiply
        operator$ = "-"
        stringmatha$ = divremainder$
        stringmathb$ = m_product$
        GOSUB string_add_subtract
        divremainder$ = stringmatha$
        operator$ = "/"
    LOOP
    IF divplace& = 0 AND divplace2& = 0 THEN divplace& = divplace3&
    IF divplace2& THEN divplace& = divplace& + divplace2& - 1
    IF quotient$ = "" THEN divplace& = 0 ' dividend is zero.
    IF divplace& OR divplace2& THEN
        quotient$ = MID$(quotient$, 1, divplace&) + "." + MID$(quotient$, divplace& + 1)
        DO UNTIL RIGHT$(quotient$, 1) <> "0"
            quotient$ = MID$(quotient$, 1, LEN(quotient$) - 1) ' Strip off trailing zeros
        LOOP
        IF RIGHT$(quotient$, 1) = "." THEN quotient$ = MID$(quotient$, 1, LEN(quotient$) - 1) ' Strip off abandoned decimal.
    END IF
    DO UNTIL LEFT$(quotient$, 1) <> "0"
        quotient$ = MID$(quotient$, 2) ' Strip off leading zeros
    LOOP
    IF quotient$ = "" THEN quotient$ = "0": divsign% = 0
    operationdivision% = 0
    stringmathb$ = quotient$: quotient$ = ""
    '''GOSUB limit_round_convert
    IF stringmathb$ = "overflow" THEN divsign% = 0: EXIT SUB
    '''GOSUB sm_converter
    runningtotal$ = stringmathb$: stringmathb$ = ""
    IF divsign% THEN runningtotal$ = "-" + runningtotal$

    IF stringmathround$ <> "" THEN runningtotal$ = runningtotal$ + stringmathround$
    EXIT SUB

    string_multiply:
    fac1$ = stringmatha$: fac2$ = stringmathb$ ' Make numbers whole numbers and remove any - sign.
    IF LEFT$(fac1$, 1) = "-" THEN fac1$ = MID$(fac1$, 2): m_sign% = -1
    IF LEFT$(fac2$, 1) = "-" THEN fac2$ = MID$(fac2$, 2): IF m_sign% THEN m_sign% = 0 ELSE m_sign% = -1
    IF INSTR(fac1$, ".") <> 0 THEN m_decimal_places& = LEN(fac1$) - INSTR(fac1$, "."): fac1$ = MID$(fac1$, 1, INSTR(fac1$, ".") - 1) + MID$(fac1$, INSTR(fac1$, ".") + 1)
    IF INSTR(fac2$, ".") <> 0 THEN m_decimal_places& = m_decimal_places& + LEN(fac2$) - INSTR(fac2$, "."): fac2$ = MID$(fac2$, 1, INSTR(fac2$, ".") - 1) + MID$(fac2$, INSTR(fac2$, ".") + 1)
    FOR m_i& = LEN(fac2$) TO 1 STEP -1 ' Multiply each charter top and bottom.
        m_k& = m_l&
        m_x2$ = MID$(fac2$, m_i&, 1)
        FOR m_j& = LEN(fac1$) TO 1 STEP -1
            m_x1$ = MID$(fac1$, m_j&, 1)
            IF m_product$ <> "" THEN
                m_add$ = LTRIM$(STR$(VAL(m_x1$) * VAL(m_x2$))) + STRING$(m_k&, "0")
                m_t& = 0: m_xproduct$ = "": m_carry% = 0
                DO ' Add multiplied characters together.
                    m_x3$ = MID$(m_add$, LEN(m_add$) - m_t&, 1)
                    m_x4$ = MID$(m_product$, LEN(m_product$) - m_t&, 1)
                    IF m_x3$ = "" AND m_x4$ = "" THEN
                        IF m_carry% THEN m_xproduct$ = "1" + m_xproduct$
                        EXIT DO
                    END IF
                    m_g% = VAL(m_x3$) + VAL(m_x4$) + m_carry%
                    IF m_g% >= 10 THEN m_g% = m_g% - 10: m_carry% = 1 ELSE m_carry% = 0
                    m_xproduct$ = LTRIM$(STR$(m_g%)) + m_xproduct$
                    m_t& = m_t& + 1
                LOOP
                m_product$ = m_xproduct$: m_xproduct$ = ""
            ELSE
                m_product$ = LTRIM$(STR$(VAL(m_x1$) * VAL(m_x2$))) + STRING$(m_k&, "0") ' First loop makes variable here.
            END IF
            m_k& = m_k& + 1 ' Adds trailing zeros multiplication
        NEXT
        m_l& = m_l& + 1 ' Used to reset value for m_k& adding one trailing zer for each loop.
    NEXT
    fac1$ = "": fac2$ = "": m_l& = 0: m_k& = 0: m_t& = 0
    IF m_decimal_places& > LEN(m_product$) THEN m_product$ = STRING$(m_decimal_places& - LEN(m_product$), "0") + m_product$ ' Add any leading zeros to a decimal. Ex: .02 * .01 is factored as 002. It needs one leading zero before adding the decimal point, .0002.
    IF m_decimal_places& AND m_product$ <> "0" THEN ' Replace any decimal point.
        m_product$ = MID$(m_product$, 1, LEN(m_product$) - m_decimal_places&) + "." + MID$(m_product$, LEN(m_product$) - m_decimal_places& + 1)
    END IF
    DO UNTIL LEFT$(m_product$, 1) <> "0" ' Remove leading zeros.
        m_product$ = MID$(m_product$, 2)
    LOOP
    IF m_decimal_places& THEN
        DO UNTIL RIGHT$(m_product$, 1) <> "0" ' Remove trailing zeros in a decimal sum.
            m_product$ = MID$(m_product$, 1, LEN(m_product$) - 1)
        LOOP
    END IF
    IF m_product$ = "" THEN m_product$ = "0": m_sign% = 0
    IF RIGHT$(m_product$, 1) = "." THEN m_product$ = MID$(m_product$, 1, LEN(m_product$) - 1) ' Remove decimal from the end of an integer total.
    IF operationdivision% THEN m_sign% = 0: RETURN
    stringmathb$ = m_product$: m_product$ = ""
    '''GOSUB limit_round_convert
    IF stringmathb$ = "overflow" THEN EXIT SUB
    '''GOSUB sm_converter
    runningtotal$ = stringmathb$: stringmathb$ = ""
    IF m_sign% THEN runningtotal$ = "-" + runningtotal$: m_sign% = 0
    RETURN

    string_add_subtract:
    IF INSTR(stringmatha$, ".") <> 0 THEN ' Evaluate sum for decimal fraction.
        sumplace& = LEN(stringmatha$) - INSTR(stringmatha$, ".")
        stringmatha$ = MID$(stringmatha$, 1, INSTR(stringmatha$, ".") - 1) + MID$(stringmatha$, INSTR(stringmatha$, ".") + 1) ' Strip out decimal
    END IF
    IF INSTR(stringmathb$, ".") <> 0 THEN ' Evaluate number for decimal fraction.
        numplace& = LEN(stringmathb$) - INSTR(stringmathb$, ".")
        stringmathb$ = MID$(stringmathb$, 1, INSTR(stringmathb$, ".") - 1) + MID$(stringmathb$, INSTR(stringmathb$, ".") + 1) ' Strip out decimal
    END IF
    IF sumplace& > numplace& THEN addsubplace& = sumplace& ELSE addsubplace& = numplace&
    IF sumplace& > addsubplace& THEN
        stringmatha$ = stringmatha$ + STRING$(sumplace& - addsubplace&, "0")
    ELSEIF addsubplace& > sumplace& THEN
        stringmatha$ = stringmatha$ + STRING$(addsubplace& - sumplace&, "0")
    END IF
    IF numplace& > addsubplace& THEN
        stringmathb$ = stringmathb$ + STRING$(numplace& - addsubplace&, "0")
    ELSEIF addsubplace& > numplace& THEN
        stringmathb$ = stringmathb$ + STRING$(addsubplace& - numplace&, "0")
    END IF ' END Decimal evaluations.

    IF LEFT$(stringmatha$, 1) = "-" THEN sign_input$ = "-" ELSE sign_input$ = "+"
    IF LEFT$(stringmathb$, 1) = "-" THEN sign_total$ = "-" ELSE sign_total$ = "+"

    addsubsign% = 0
    SELECT CASE sign_input$ + operator$ + sign_total$
        CASE "+++", "+--"
            operator$ = "+"
            IF LEFT$(stringmathb$, 1) = "-" THEN stringmathb$ = MID$(stringmathb$, 2)
        CASE "++-", "+-+"
            operator$ = "-"
            IF LEFT$(stringmathb$, 1) = "-" THEN stringmathb$ = MID$(stringmathb$, 2)
            IF VAL(stringmathb$) > VAL(stringmatha$) THEN SWAP stringmatha$, stringmathb$: addsubsign% = -1
        CASE "---", "-++"
            operator$ = "-"
            IF LEFT$(stringmatha$, 1) = "-" THEN stringmatha$ = MID$(stringmatha$, 2)
            IF LEFT$(stringmathb$, 1) = "-" THEN stringmathb$ = MID$(stringmathb$, 2)
            IF VAL(stringmathb$) > VAL(stringmatha$) THEN SWAP stringmatha$, stringmathb$ ELSE addsubsign% = -1
        CASE "--+", "-+-"
            operator$ = "+"
            IF LEFT$(stringmatha$, 1) = "-" THEN stringmatha$ = MID$(stringmatha$, 2)
            IF LEFT$(stringmathb$, 1) = "-" THEN stringmathb$ = MID$(stringmathb$, 2)
            addsubsign% = -1
    END SELECT

    IF LEN(stringmatha$) > LEN(stringmathb$) THEN
        stringmathb$ = STRING$(LEN(stringmatha$) - LEN(stringmathb$), "0") + stringmathb$
    ELSEIF LEN(stringmatha$) < LEN(stringmathb$) THEN
        stringmatha$ = STRING$(LEN(stringmathb$) - LEN(stringmatha$), "0") + stringmatha$
    END IF
    addsubx1$ = ""

    SELECT CASE operator$
        CASE "+", "="
            FOR addsubii& = LEN(stringmatha$) TO 1 STEP -1
                addsubx1% = VAL(MID$(stringmatha$, addsubii&, 1)) + VAL(MID$(stringmathb$, addsubii&, 1)) + addsubcarry%
                IF addsubx1% > 9 THEN addsubx1% = addsubx1% - 10: addsubcarry% = 1 ELSE addsubcarry% = 0
                addsubx1$ = LTRIM$(STR$(addsubx1%)) + addsubx1$
            NEXT
            IF addsubcarry% THEN addsubx1$ = "1" + addsubx1$: addsubcarry% = 0
            GOSUB replace_decimal
        CASE "-"
            FOR addsubii& = LEN(stringmatha$) TO 1 STEP -1
                addsubx1% = VAL(MID$(stringmatha$, addsubii&, 1)) - VAL(MID$(stringmathb$, addsubii&, 1)) + addsubcarry%
                IF addsubx1% < 0 THEN addsubx1% = addsubx1% + 10: addsubcarry% = -1 ELSE addsubcarry% = 0
                addsubx1$ = LTRIM$(STR$(addsubx1%)) + addsubx1$
            NEXT
            IF addsubx1$ <> "" AND addsubx1$ <> STRING$(LEN(addsubx1$), "0") THEN GOSUB replace_decimal
            DO UNTIL LEFT$(addsubx1$, 1) <> "0" ' Remove leading zeros.
                addsubx1$ = MID$(addsubx1$, 2)
            LOOP
            IF addsubx1$ = "" THEN
                addsubx1$ = "0": addsubsign% = 0
            ELSE
                IF addsubcarry% THEN addsubx1$ = "-" + addsubx1$: addsubcarry% = 0
            END IF
    END SELECT

    IF addsubsign% THEN
        IF LEFT$(addsubx1$, 1) = "-" THEN addsubx1$ = MID$(addsubx1$, 2) ELSE addsubx1$ = "-" + addsubx1$
    END IF
    stringmatha$ = addsubx1$: addsubx1$ = ""
    IF operationdivision% THEN RETURN
    stringmathb$ = stringmatha$: stringmatha$ = ""
    IF LEFT$(stringmathb$, 1) = "-" THEN
        stringmathb$ = MID$(stringmathb$, 2)
        n2sign$ = "-"
    ELSE
        n2sign$ = ""
    END IF
    ''' GOSUB limit_round_convert
    IF stringmathb$ = "overflow" THEN n2sign$ = "": EXIT SUB
    ''' GOSUB sm_converter
    runningtotal$ = n2sign$ + stringmathb$: n2sign$ = ""
    RETURN

    replace_decimal:
    IF addsubplace& THEN
        addsubx1$ = STRING$(addsubplace& - LEN(addsubx1$), "0") + addsubx1$
        addsubx1$ = MID$(addsubx1$, 1, LEN(addsubx1$) - addsubplace&) + "." + MID$(addsubx1$, LEN(addsubx1$) - addsubplace& + 1)
        DO UNTIL RIGHT$(addsubx1$, 1) <> "0" ' Remove trailing zeros in a decimal sum.
            addsubx1$ = MID$(addsubx1$, 1, LEN(addsubx1$) - 1)
            addsubplace& = addsubplace& - 1
        LOOP
        IF RIGHT$(addsubx1$, 1) = "." THEN addsubx1$ = MID$(addsubx1$, 1, LEN(addsubx1$) - 1) ' Number is now an integer.
    END IF
    RETURN

END SUB


For you math folks, if you have a more elegant way to do this, I'd love to see it. Also, please excuse the message for "Eventual infinite repetend." I used this made up term to describe fractions like 1 / 6 where the digits repeat, but not immediately following the decimal point like 1 / 3 does. If you know the correct term for this type of repetend, please let me know.

Pete
Reply
#2
I did this years ago, I wonder if I could dig it up. In fact I did this with base 2 numbers! Because drawing the bar codes made some fabulous designs.

Ah I did find it in no time! Search divide and there under math/division is, n divided by d:
Code: (Select All)
_Title "n slash d to R notation and back again" '2019-04-24
' from:"Decimal Expansion of Division without Dividing  by bplus 2017-12-03"
' dove tailing Adrians and my recent dividing programs

' 2019-04-24
' I want to isolate the repeated section immediately not write the fraction out and then repeat the repeated section
' not 1/6 = .16R6 >>> but .1R6

'hmm... look like have to cycle through twice to get the length of the repeat section
' but before returning backup to start of repeat section insert the R where it starts the first time
' and end it where " repeat " starts.

'2019-04-24
' just for kicks, convert the R notation back to fraction if possible.
' Had to revert back to the redundant " repeat " form of R notation.

'2019-04-27 Thanks to Jack002's comments and replies this code to calculate adj&& may have been improved.

Randomize Timer
DefLng A-Z
Do
    Print: Print "Enter 2 integers < 3200, numerator / denominator, 0's quit, don't forget / "
    Input nd$
    slash = InStr(nd$, "/")
    If slash Then
        dvsr = Val(Mid$(nd$, slash + 1))
        If dvsr = 0 Then Print "Divisor is 0, bye.": End
        numerator = Val(Mid$(nd$, 1, slash - 1))
        If numerator = 0 Then Print "Numerator is 0, bye.": End
    Else
        Print "No slash found, bye.": End
    End If
    Cls
    d$ = divide$(numerator, dvsr)
    Print numerator; " / "; dvsr; " = "; d$

    'and now arttemp"t to convert back to fraction
    Print: Print "Check if can convert back to fraction:"
    result$ = convertRnotation2Fraction$(d$)
    If result$ <> "" Then Print result$
Loop

Function convertRnotation2Fraction$ (rNotedDecimal$)
    'check if R in the decimal
    dotPos = InStr(rNotedDecimal$, ".")
    If dotPos = 0 Then convertRnotation2Fraction$ = rNotedDecimal$: Exit Function
    RPos = InStr(rNotedDecimal$, " repeat ")
    If RPos = 0 Then convertRnotation2Fraction$ = convert2Fraction$(rNotedDecimal$): Exit Function

    'still here? we have an R and a decimal
    whole$ = Mid$(rNotedDecimal$, 1, dotPos - 1)
    If Val(whole$) = 0 Then whole$ = ""

    p = Len(rNotedDecimal$) - RPos - Len(" repeat ") + 1
    Print "Debug: repeat length ="; p
    If p > 12 Then
        Print "The length of the repeat section of: "
        Print rNotedDecimal$
        Print " is too long to convert back to fraction."
        Exit Function
    End If

    dec$ = Mid$(rNotedDecimal$, dotPos)
    Print "Debug: converting dec$ "; dec$

    'remove " repeat "
    RPos = InStr(dec$, " repeat ")
    dec1$ = Mid$(dec$, 1, RPos - 1) + Mid$(dec$, RPos + Len(" repeat "))
    dec2$ = Mid$(dec$, 1, RPos - 1)
    Print "Debug: dec1$ (double repeat), dec2$ (single repeat) = "; dec1$; ", "; dec2$

    'mult by 10^p to get the 2nd repeat part in dec1$ aligned to 1st repeat part  in dec2$
    vd1## = Val(dec1$) * 10 ^ p
    vd2## = Val(dec2$)
    n## = vd1## - vd2## 'subtract dec2$ from dec1$

    'adj&& = 1 'convert to whole numbers
    'WHILE n## <> INT(n##)
    '    adj&& = adj&& * 10
    '    n## = n## * 10
    'WEND

    'calculate adj&& from length of decimal
    ns$ = Str$(n##)
    dot = InStr(ns$, ".")
    p2 = Len(ns$) - dot
    adj&& = 10 ^ p2

    'reevaluate to avoid rounding errors from crazy floating point math
    n1&& = vd1## * adj&& - vd2## * adj&&
    Print "Debug values: vd1, vd2, adj&&, n1&& (difference * adj&& for whole number):"
    Print vd1##; ", "; vd2##; ", "; adj&&; ", "; n1&&

    d&& = (10 ^ p - 1) * adj&&
    Print "Debug: Giant numerator, denominator "; n1&&; ", "; d&& 'giant numbers

    'reduce giant numbers by Gretaest Common Divisor between them
    g&& = gcd&&(n1&&, d&&): sn&& = n1&& / g&&: sd&& = d&& / g&&

    convertRnotation2Fraction$ = whole$ + " " + _Trim$(Str$(sn&&)) + "/" + _Trim$(Str$(sd&&))
End Function

Function convert2Fraction$ (decimal$)
    dot%% = InStr(decimal$, ".")
    If dot%% > 0 Then
        whole$ = Mid$(decimal$, 1, dot%% - 1)
        If Val(whole$) = 0 Then whole$ = ""
        p%% = Len(decimal$) - dot%%
        n&& = Val(Mid$(decimal$, dot%% + 1))
        d&& = 10 ^ p%%
        g&& = gcd&&(n&&, d&&): sn&& = n&& / g&&: sd&& = d&& / g&&
        convert2Fraction$ = whole$ + " " + _Trim$(Str$(sn&&)) + "/" + _Trim$(Str$(sd&&))
    Else
        convert2Fraction$ = decimal$
    End If
End Function

Function gcd&& (a&&, b&&)
    'a and b will be changed unless make copies
    c&& = a&&: d&& = b&&
    While c&& <> 0 And d&& <> 0
        If c&& > d&& Then c&& = c&& Mod d&& Else d&& = d&& Mod c&&
    Wend
    gcd&& = c&& + d&&
End Function


Function divide$ (n, d)
    'n = original product or numerator (preserve value of n)
    'd = divisor  (also preserve value)
    c = n 'copy of n to be reduced until <= d, c will be the remainder part of division
    a = 0 'a is for answer or accumulate, the integer part of the division result

    'find lowest power of 10 such that: d * 10^p > n
    p = 0 'power of 10
    While d * (10 ^ p) < n
        p = p + 1
    Wend
    While c >= d
        If c = d Then a = a + 1: c = 0: Exit While
        p = p - 1
        If p >= 0 Then
            m = 0
            While d * m * 10 ^ p < c
                m = m + 1
            Wend
            m = m - 1
            c = c - d * m * 10 ^ p
            a = a + m * 10 ^ p
        End If
    Wend

    'Now for the decimal expansion isolating the repeating part if one
    If c <> 0 Then
        Dim b(d)
        b$ = "."
        While c <> 0

            'emergency bug out!
            loopct = loopct + 1 'loop count should not exceed 1000 for numbers I am testing
            If loopct > 1000 Then Print "Error: loop too long, bugging out! ": GoTo skip

            'track repeats  b() tracks been here once, b2() tracks been here twice
            If b(c) = 1 Then 'been here!
                If rFlag = 1 Then 'been here twice!
                    If b2(c) = 1 Then Exit While 'strike 3, we're out of here
                    b2(c) = 1
                Else
                    rFlag = 1
                    Dim b2(d)
                    b$ = b$ + " repeat "
                    b2(c) = 1
                End If
            Else
                b(c) = 1
            End If

            'c was last remainder, mult by 10 and see if some m * d > can reduce it
            tc = 10 * c
            flag = 0
            For m = 0 To 9
                If ((tc - m * d) >= 0) And ((tc - (m + 1) * d) < 0) Then
                    flag = 1: b$ = b$ + LTrim$(Str$(m))
                    Exit For
                End If
            Next
            If flag = 0 Then b$ = b$ + "0": m = 0
            c = tc - d * m
        Wend
    End If

    'OK either d divided n eventually or there is a repeated pattern recorded in b$
    skip: '< needed for debugging
    r$ = Str$(a)
    If b$ <> "" Then r$ = r$ + b$
    divide$ = r$
End Function

The repeating part is isolated and named and measured.


1/97 you are just getting started 1/269 is 268 long 1/(big prim number) always a good bet to be long.
b = b + ...
Reply
#3
I hope you have it handy.

I just tweaked what I have just a bit. The original works, but I fudged it a bit. Right now, 1 / 6 = .1666 (6s repeat) and 1 / 7 = .142857... So I made the algorithm look past the first digit so it would see .666... and .428571... That would be fine for detecting the pattern further into the decimal, well, fine until you wanted to assign a variable to show the repetend.

So...

Code: (Select All)
WIDTH 170, 42
_SCREENMOVE 0, 0
DO
    DIM SHARED runningtotal$, limit&&
    limit&& = 200

    LINE INPUT "Numerator: "; a$
    LINE INPUT "Denominator: "; b$

    calcdiv a$, b$

    COLOR 14, 0: PRINT runningtotal$; "  ";: COLOR 7, 0

    IF INSTR(runningtotal$, ".") THEN
        x$ = MID$(runningtotal$, INSTR(runningtotal$, ".") + 1)
        x$ = MID$(x$, LEN(b$) - LEN(a$))

        FOR i = 1 TO LEN(x$)
            k = j
            j = INSTR(i + 1, x$, MID$(x$, 1, i))
            IF j = k THEN EXIT FOR
        NEXT

        SELECT CASE j
            CASE 0
                IF LEN(x$) >= limit&& AND INSTR(runningtotal$, STRING$(limit&&, MID$(x$, LEN(x$), 1))) THEN
                    IF x$ <> STRING$(LEN(x$), MID$(x$, 1, 1)) THEN
                        msg$ = "Eventual infinite repetend."
                        repetend$ = STRING$(3, MID$(x$, LEN(x$), 1))
                    ELSE
                        msg$ = "Repetend infinite."
                        repetend$ = STRING$(3, MID$(x$, LEN(x$), 1))
                    END IF
                ELSE
                    j = -1: msg$ = "Non-repetend."
                END IF
            CASE ELSE
                msg$ = "Repetend length = " + LTRIM$(STR$(j - 1))
                repetend$ = MID$(x$, 1, j - 1)
        END SELECT
    ELSE
        j = -1: msg$ = "Non-decimal"
    END IF

    PRINT msg$; "  ";
    COLOR 3, 0
    PRINT repetend$;: IF j = 0 THEN PRINT "..." ELSE PRINT
    COLOR 7, 0
    CLEAR
    PRINT
LOOP

SUB calcdiv (a$, b$)
    stringmatha$ = a$
    stringmathb$ = b$

    operationdivision% = -1
    divbuffer& = LEN(stringmathb$) - LEN(stringmatha$)
    IF divbuffer& < 0 THEN divbuffer& = 0
    d2dividend$ = stringmatha$
    d1divisor$ = stringmathb$
    IF LEFT$(d1divisor$, 1) = "0" AND LEN(d1divisor$) = 1 THEN PRINT "Division by zero not allowed.": EXIT SUB
    IF LEFT$(d1divisor$, 1) = "-" THEN divsign% = -1: d1divisor$ = MID$(d1divisor$, 2)
    IF LEFT$(d2dividend$, 1) = "-" THEN
        IF divsign% THEN
            divsign% = 0
        ELSE
            divsign% = -1
        END IF
        d2dividend$ = MID$(d2dividend$, 2)
    END IF
    IF INSTR(d1divisor$, ".") <> 0 THEN
        DO UNTIL RIGHT$(d1divisor$, 1) <> "0"
            d1divisor$ = MID$(d1divisor$, 1, LEN(d1divisor$) - 1) ' Strip off trailing zeros
        LOOP
        divplace& = LEN(d1divisor$) - INSTR(d1divisor$, ".")
        d1divisor$ = MID$(d1divisor$, 1, INSTR(d1divisor$, ".") - 1) + MID$(d1divisor$, INSTR(d1divisor$, ".") + 1) ' Strip off decimal point.
        DO UNTIL LEFT$(d1divisor$, 1) <> "0"
            d1divisor$ = MID$(d1divisor$, 2) ' Strip off leading zeros for divisors smaller than .1
        LOOP
    END IF

    IF INSTR(d2dividend$, ".") <> 0 THEN
        d2dividend$ = d2dividend$ + STRING$(divplace& - LEN(d2dividend$) - INSTR(d2dividend$, "."), "0") ' Add any zeros based on the length of dividend at decimal - length of divisor at decimal. If less than zero, nothing added.
        divplace2& = INSTR(d2dividend$, ".")
        DO UNTIL RIGHT$(d2dividend$, 1) <> "0"
            d2dividend$ = MID$(d2dividend$, 1, LEN(d2dividend$) - 1) ' Strip off trailing zeros
        LOOP
        d2dividend$ = MID$(d2dividend$, 1, INSTR(d2dividend$, ".") - 1) + MID$(d2dividend$, INSTR(d2dividend$, ".") + 1) ' Strip off decimal point.
    ELSE
        d2dividend$ = d2dividend$ + STRING$(divplace&, "0") ' Add any zeros based on the length of dividend at decimal - length of divisor at decimal. If less than zero, nothing added.
        divplace& = 0
    END IF
    DO
        DO
            divremainder& = divremainder& + 1: divremainder$ = divremainder$ + MID$(d2dividend$, divremainder&, 1)
            IF MID$(d2dividend$, divremainder&, 1) = "" THEN
                IF divremainder$ = STRING$(LEN(divremainder$), "0") AND LEN(quotient$) > LEN(d2dividend$) THEN divflag% = -1: EXIT DO
                divcarry& = divcarry& + 1
                IF divcarry& = 1 THEN divplace3& = divremainder& - 1
                IF divcarry& > limit&& + 1 + divbuffer& THEN
                    divflag% = -2: EXIT DO
                END IF
                divremainder$ = divremainder$ + "0" ' No more digits to bring down.
            END IF
            IF LEN(divremainder$) > LEN(d1divisor$) OR LEN(divremainder$) = LEN(d1divisor$) AND divremainder$ >= d1divisor$ THEN EXIT DO
            quotient$ = quotient$ + "0"
        LOOP
        IF divflag% THEN divflag% = 0: EXIT DO
        FOR div_i% = 9 TO 1 STEP -1
            stringmatha$ = LTRIM$(STR$(div_i%)): stringmathb$ = d1divisor$
            m_product$ = "": GOSUB string_multiply
            tempcutd$ = divremainder$ ' divremainder$ can be 00 or other leading zero values.
            DO
                IF LEN(tempcutd$) = 1 THEN EXIT DO
                IF LEFT$(tempcutd$, 1) = "0" THEN
                    tempcutd$ = MID$(tempcutd$, 2)
                ELSE
                    EXIT DO
                END IF
            LOOP
            IF LEN(tempcutd$) > LEN(m_product$) OR LEN(tempcutd$) = LEN(m_product$) AND m_product$ <= tempcutd$ THEN EXIT FOR
        NEXT
        quotient$ = quotient$ + LTRIM$(STR$(div_i%))
        stringmatha$ = LTRIM$(STR$(div_i%)): stringmathb$ = d1divisor$
        m_product$ = "": GOSUB string_multiply
        operator$ = "-"
        stringmatha$ = divremainder$
        stringmathb$ = m_product$
        GOSUB string_add_subtract
        divremainder$ = stringmatha$
        operator$ = "/"
    LOOP
    IF divplace& = 0 AND divplace2& = 0 THEN divplace& = divplace3&
    IF divplace2& THEN divplace& = divplace& + divplace2& - 1
    IF quotient$ = "" THEN divplace& = 0 ' dividend is zero.
    IF divplace& OR divplace2& THEN
        quotient$ = MID$(quotient$, 1, divplace&) + "." + MID$(quotient$, divplace& + 1)
        DO UNTIL RIGHT$(quotient$, 1) <> "0"
            quotient$ = MID$(quotient$, 1, LEN(quotient$) - 1) ' Strip off trailing zeros
        LOOP
        IF RIGHT$(quotient$, 1) = "." THEN quotient$ = MID$(quotient$, 1, LEN(quotient$) - 1) ' Strip off abandoned decimal.
    END IF
    DO UNTIL LEFT$(quotient$, 1) <> "0"
        quotient$ = MID$(quotient$, 2) ' Strip off leading zeros
    LOOP
    IF quotient$ = "" THEN quotient$ = "0": divsign% = 0
    operationdivision% = 0
    stringmathb$ = quotient$: quotient$ = ""
    '''GOSUB limit_round_convert
    IF stringmathb$ = "overflow" THEN divsign% = 0: EXIT SUB
    '''GOSUB sm_converter
    runningtotal$ = stringmathb$: stringmathb$ = ""
    IF divsign% THEN runningtotal$ = "-" + runningtotal$

    IF stringmathround$ <> "" THEN runningtotal$ = runningtotal$ + stringmathround$
    EXIT SUB

    string_multiply:
    fac1$ = stringmatha$: fac2$ = stringmathb$ ' Make numbers whole numbers and remove any - sign.
    IF LEFT$(fac1$, 1) = "-" THEN fac1$ = MID$(fac1$, 2): m_sign% = -1
    IF LEFT$(fac2$, 1) = "-" THEN fac2$ = MID$(fac2$, 2): IF m_sign% THEN m_sign% = 0 ELSE m_sign% = -1
    IF INSTR(fac1$, ".") <> 0 THEN m_decimal_places& = LEN(fac1$) - INSTR(fac1$, "."): fac1$ = MID$(fac1$, 1, INSTR(fac1$, ".") - 1) + MID$(fac1$, INSTR(fac1$, ".") + 1)
    IF INSTR(fac2$, ".") <> 0 THEN m_decimal_places& = m_decimal_places& + LEN(fac2$) - INSTR(fac2$, "."): fac2$ = MID$(fac2$, 1, INSTR(fac2$, ".") - 1) + MID$(fac2$, INSTR(fac2$, ".") + 1)
    FOR m_i& = LEN(fac2$) TO 1 STEP -1 ' Multiply each charter top and bottom.
        m_k& = m_l&
        m_x2$ = MID$(fac2$, m_i&, 1)
        FOR m_j& = LEN(fac1$) TO 1 STEP -1
            m_x1$ = MID$(fac1$, m_j&, 1)
            IF m_product$ <> "" THEN
                m_add$ = LTRIM$(STR$(VAL(m_x1$) * VAL(m_x2$))) + STRING$(m_k&, "0")
                m_t& = 0: m_xproduct$ = "": m_carry% = 0
                DO ' Add multiplied characters together.
                    m_x3$ = MID$(m_add$, LEN(m_add$) - m_t&, 1)
                    m_x4$ = MID$(m_product$, LEN(m_product$) - m_t&, 1)
                    IF m_x3$ = "" AND m_x4$ = "" THEN
                        IF m_carry% THEN m_xproduct$ = "1" + m_xproduct$
                        EXIT DO
                    END IF
                    m_g% = VAL(m_x3$) + VAL(m_x4$) + m_carry%
                    IF m_g% >= 10 THEN m_g% = m_g% - 10: m_carry% = 1 ELSE m_carry% = 0
                    m_xproduct$ = LTRIM$(STR$(m_g%)) + m_xproduct$
                    m_t& = m_t& + 1
                LOOP
                m_product$ = m_xproduct$: m_xproduct$ = ""
            ELSE
                m_product$ = LTRIM$(STR$(VAL(m_x1$) * VAL(m_x2$))) + STRING$(m_k&, "0") ' First loop makes variable here.
            END IF
            m_k& = m_k& + 1 ' Adds trailing zeros multiplication
        NEXT
        m_l& = m_l& + 1 ' Used to reset value for m_k& adding one trailing zer for each loop.
    NEXT
    fac1$ = "": fac2$ = "": m_l& = 0: m_k& = 0: m_t& = 0
    IF m_decimal_places& > LEN(m_product$) THEN m_product$ = STRING$(m_decimal_places& - LEN(m_product$), "0") + m_product$ ' Add any leading zeros to a decimal. Ex: .02 * .01 is factored as 002. It needs one leading zero before adding the decimal point, .0002.
    IF m_decimal_places& AND m_product$ <> "0" THEN ' Replace any decimal point.
        m_product$ = MID$(m_product$, 1, LEN(m_product$) - m_decimal_places&) + "." + MID$(m_product$, LEN(m_product$) - m_decimal_places& + 1)
    END IF
    DO UNTIL LEFT$(m_product$, 1) <> "0" ' Remove leading zeros.
        m_product$ = MID$(m_product$, 2)
    LOOP
    IF m_decimal_places& THEN
        DO UNTIL RIGHT$(m_product$, 1) <> "0" ' Remove trailing zeros in a decimal sum.
            m_product$ = MID$(m_product$, 1, LEN(m_product$) - 1)
        LOOP
    END IF
    IF m_product$ = "" THEN m_product$ = "0": m_sign% = 0
    IF RIGHT$(m_product$, 1) = "." THEN m_product$ = MID$(m_product$, 1, LEN(m_product$) - 1) ' Remove decimal from the end of an integer total.
    IF operationdivision% THEN m_sign% = 0: RETURN
    stringmathb$ = m_product$: m_product$ = ""
    '''GOSUB limit_round_convert
    IF stringmathb$ = "overflow" THEN EXIT SUB
    '''GOSUB sm_converter
    runningtotal$ = stringmathb$: stringmathb$ = ""
    IF m_sign% THEN runningtotal$ = "-" + runningtotal$: m_sign% = 0
    RETURN

    string_add_subtract:
    IF INSTR(stringmatha$, ".") <> 0 THEN ' Evaluate sum for decimal fraction.
        sumplace& = LEN(stringmatha$) - INSTR(stringmatha$, ".")
        stringmatha$ = MID$(stringmatha$, 1, INSTR(stringmatha$, ".") - 1) + MID$(stringmatha$, INSTR(stringmatha$, ".") + 1) ' Strip out decimal
    END IF
    IF INSTR(stringmathb$, ".") <> 0 THEN ' Evaluate number for decimal fraction.
        numplace& = LEN(stringmathb$) - INSTR(stringmathb$, ".")
        stringmathb$ = MID$(stringmathb$, 1, INSTR(stringmathb$, ".") - 1) + MID$(stringmathb$, INSTR(stringmathb$, ".") + 1) ' Strip out decimal
    END IF
    IF sumplace& > numplace& THEN addsubplace& = sumplace& ELSE addsubplace& = numplace&
    IF sumplace& > addsubplace& THEN
        stringmatha$ = stringmatha$ + STRING$(sumplace& - addsubplace&, "0")
    ELSEIF addsubplace& > sumplace& THEN
        stringmatha$ = stringmatha$ + STRING$(addsubplace& - sumplace&, "0")
    END IF
    IF numplace& > addsubplace& THEN
        stringmathb$ = stringmathb$ + STRING$(numplace& - addsubplace&, "0")
    ELSEIF addsubplace& > numplace& THEN
        stringmathb$ = stringmathb$ + STRING$(addsubplace& - numplace&, "0")
    END IF ' END Decimal evaluations.

    IF LEFT$(stringmatha$, 1) = "-" THEN sign_input$ = "-" ELSE sign_input$ = "+"
    IF LEFT$(stringmathb$, 1) = "-" THEN sign_total$ = "-" ELSE sign_total$ = "+"

    addsubsign% = 0
    SELECT CASE sign_input$ + operator$ + sign_total$
        CASE "+++", "+--"
            operator$ = "+"
            IF LEFT$(stringmathb$, 1) = "-" THEN stringmathb$ = MID$(stringmathb$, 2)
        CASE "++-", "+-+"
            operator$ = "-"
            IF LEFT$(stringmathb$, 1) = "-" THEN stringmathb$ = MID$(stringmathb$, 2)
            IF VAL(stringmathb$) > VAL(stringmatha$) THEN SWAP stringmatha$, stringmathb$: addsubsign% = -1
        CASE "---", "-++"
            operator$ = "-"
            IF LEFT$(stringmatha$, 1) = "-" THEN stringmatha$ = MID$(stringmatha$, 2)
            IF LEFT$(stringmathb$, 1) = "-" THEN stringmathb$ = MID$(stringmathb$, 2)
            IF VAL(stringmathb$) > VAL(stringmatha$) THEN SWAP stringmatha$, stringmathb$ ELSE addsubsign% = -1
        CASE "--+", "-+-"
            operator$ = "+"
            IF LEFT$(stringmatha$, 1) = "-" THEN stringmatha$ = MID$(stringmatha$, 2)
            IF LEFT$(stringmathb$, 1) = "-" THEN stringmathb$ = MID$(stringmathb$, 2)
            addsubsign% = -1
    END SELECT

    IF LEN(stringmatha$) > LEN(stringmathb$) THEN
        stringmathb$ = STRING$(LEN(stringmatha$) - LEN(stringmathb$), "0") + stringmathb$
    ELSEIF LEN(stringmatha$) < LEN(stringmathb$) THEN
        stringmatha$ = STRING$(LEN(stringmathb$) - LEN(stringmatha$), "0") + stringmatha$
    END IF
    addsubx1$ = ""

    SELECT CASE operator$
        CASE "+", "="
            FOR addsubii& = LEN(stringmatha$) TO 1 STEP -1
                addsubx1% = VAL(MID$(stringmatha$, addsubii&, 1)) + VAL(MID$(stringmathb$, addsubii&, 1)) + addsubcarry%
                IF addsubx1% > 9 THEN addsubx1% = addsubx1% - 10: addsubcarry% = 1 ELSE addsubcarry% = 0
                addsubx1$ = LTRIM$(STR$(addsubx1%)) + addsubx1$
            NEXT
            IF addsubcarry% THEN addsubx1$ = "1" + addsubx1$: addsubcarry% = 0
            GOSUB replace_decimal
        CASE "-"
            FOR addsubii& = LEN(stringmatha$) TO 1 STEP -1
                addsubx1% = VAL(MID$(stringmatha$, addsubii&, 1)) - VAL(MID$(stringmathb$, addsubii&, 1)) + addsubcarry%
                IF addsubx1% < 0 THEN addsubx1% = addsubx1% + 10: addsubcarry% = -1 ELSE addsubcarry% = 0
                addsubx1$ = LTRIM$(STR$(addsubx1%)) + addsubx1$
            NEXT
            IF addsubx1$ <> "" AND addsubx1$ <> STRING$(LEN(addsubx1$), "0") THEN GOSUB replace_decimal
            DO UNTIL LEFT$(addsubx1$, 1) <> "0" ' Remove leading zeros.
                addsubx1$ = MID$(addsubx1$, 2)
            LOOP
            IF addsubx1$ = "" THEN
                addsubx1$ = "0": addsubsign% = 0
            ELSE
                IF addsubcarry% THEN addsubx1$ = "-" + addsubx1$: addsubcarry% = 0
            END IF
    END SELECT

    IF addsubsign% THEN
        IF LEFT$(addsubx1$, 1) = "-" THEN addsubx1$ = MID$(addsubx1$, 2) ELSE addsubx1$ = "-" + addsubx1$
    END IF
    stringmatha$ = addsubx1$: addsubx1$ = ""
    IF operationdivision% THEN RETURN
    stringmathb$ = stringmatha$: stringmatha$ = ""
    IF LEFT$(stringmathb$, 1) = "-" THEN
        stringmathb$ = MID$(stringmathb$, 2)
        n2sign$ = "-"
    ELSE
        n2sign$ = ""
    END IF
    ''' GOSUB limit_round_convert
    IF stringmathb$ = "overflow" THEN n2sign$ = "": EXIT SUB
    ''' GOSUB sm_converter
    runningtotal$ = n2sign$ + stringmathb$: n2sign$ = ""
    RETURN

    replace_decimal:
    IF addsubplace& THEN
        addsubx1$ = STRING$(addsubplace& - LEN(addsubx1$), "0") + addsubx1$
        addsubx1$ = MID$(addsubx1$, 1, LEN(addsubx1$) - addsubplace&) + "." + MID$(addsubx1$, LEN(addsubx1$) - addsubplace& + 1)
        DO UNTIL RIGHT$(addsubx1$, 1) <> "0" ' Remove trailing zeros in a decimal sum.
            addsubx1$ = MID$(addsubx1$, 1, LEN(addsubx1$) - 1)
            addsubplace& = addsubplace& - 1
        LOOP
        IF RIGHT$(addsubx1$, 1) = "." THEN addsubx1$ = MID$(addsubx1$, 1, LEN(addsubx1$) - 1) ' Number is now an integer.
    END IF
    RETURN

END SUB

Pete
If eggs are brain food, Biden takes his scrambled.
Reply
#4
Yeah, this is definitely a fruitful exercise to work out on your own with Basic.
b = b + ...
Reply
#5
I've implemented this into the calculator, but without knowing the rules and if my algorithms are the same as those used by precision calculators I feel like I may be wasting my time. For instance...

1 / 3 will be reported as .333... (Actually, the last digit gets rounded down and since that is zero, the trailing zero digit is removed.

1 / 6 will be reported as .16667 (The last digit of 6 is rounded up to 7.)

So I would have to adjust my calculator to display .16667 but keep in memory .1666... for the next calculation.

Weird, but some online calculators will not allow you to divide and multiply back to get to the same number. For instance:

https://calculator-1.com/

1 / 3 = .333... * 3 = .999... instead of 1!

I think the better calculators display rounded but base the next calculation on the un-rounded result, so 1 / 3 = .333... * 3 = 1.

I really wish I could find the accepted math algorithm that allows for several divisions of a number would result in the original number using the same numbers to multiply in reverse order.

1 / 6 / 3 / 7 / 9 * 9 * 7 * 3 * 6 = 1

I'm very close, but still not quite there yet.

Pete
Reply
#6
hi Pete
the Windows Calculator is open source https://github.com/microsoft/calculator
it seems to be written in C#
Quote:Infinite precision for basic arithmetic operations (addition, subtraction, multiplication, division) so that calculations never lose precision.
I tried to find where in the source the math is performed but failed to find it
Reply
#7
I tried do view the code for the windows calculator, but my browser wouldn't load it.

So I had a couple of tests that required me to rethink the repetend routine a bit.

Here is where I'm at so far with a few test cases included. It works on all of these. If you can find a repetition that breaks it, let me know.

Also, I'm trying to figure out if I should bother with times where there are not enough digits reported to fully identify a repeating decimal. If so, how many repeating digits would be enough to would be a repetend if more digits were reported?

Code: (Select All)
_SCREENMOVE 0, 0
WIDTH 160, 42
DO
    p = p + 1
    SELECT CASE p
        CASE 1: a$ = ".0033125"
        CASE 2: a$ = "33125"
        CASE 3: a$ = ".331253312533125"
        CASE 4: a$ = ".00000331253312533125"
        CASE 5: a$ = ".333"
        CASE 6: a$ = ".000001666"
        CASE 7: a$ = ".00000333"
        CASE 8: a$ = "3.141592174932847"
        CASE 9: a$ = "6.00000011127501112750111275"
        CASE 10: a$ = ".01111411111411114111114"
        CASE 11: a$ = ".000881834215167548500881834215167548500881834215167548500881834215167"
        CASE ELSE
            END
    END SELECT

    a$ = MID$(a$, INSTR(a$, ".") + 1)
    i = 1: j = 0: k = 0
    DO
        j = j + 1: k = k + 1
        z$ = MID$(a$, i, j)
        mp% = INSTR(LEN(z$) + i, a$, z$)
        REM COLOR 14, 0: PRINT z$, "i ="; i; "Len ="; LEN(z$); "Prog ="; i + LEN(z$); "mp% ="; mp%; "case ="; p; a$: COLOR 7, 0: SLEEP
        IF VAL(z$) AND mp% = LEN(z$) + i THEN
            FOR k = 0 TO LEN(MID$(a$, i)) / LEN(z$) - 1
                IF MID$(a$, i + k * LEN(z$), LEN(z$)) <> z$ THEN mp% = -1: EXIT FOR
            NEXT
            IF mp% > 0 THEN
                SELECT CASE LEN(z$)
                    CASE 1
                        IF i = 1 THEN
                            msg$ = "Repetend infinite: " + STRING$(3, z$) + "..."
                        ELSE
                            msg$ = "Repetend eventually infinite: " + STRING$(3, z$) + "..."
                        END IF
                    CASE ELSE
                        msg$ = "Repetend " + z$ + " " + "length = " + LTRIM$(STR$(LEN(z$)))
                END SELECT
                EXIT DO
            END IF
        END IF
        IF LEN(z$) >= LEN(a$) - i + 1 / 2 THEN msg$ = "Non-repetend.": EXIT DO
        IF mp% = 0 THEN j = 0: i = i + 1
    LOOP
    PRINT msg$, a$: PRINT
LOOP
Reply
#8
Pete I can't answer that, on the other hand, have heard of posit/unum's ?
Dr. John L. Gustafson http://web.stanford.edu/class/ee380/Abst...70201.html came up with a different way to do computer arithmetic
here's a 1 and 1/2 hour video https://youtu.be/aP0Y1uAA-2Y
Wikipedia https://en.wikipedia.org/wiki/Unum_(number_format)
Reply
#9
(08-03-2022, 01:39 AM)Jack Wrote: Pete I can't answer that, on the other hand, have heard of posit/unum's ?
Dr. John L. Gustafson http://web.stanford.edu/class/ee380/Abst...70201.html came up with a different way to do computer arithmetic
here's a 1 and 1/2 hour video https://youtu.be/aP0Y1uAA-2Y
Wikipedia https://en.wikipedia.org/wiki/Unum_(number_format)

Trying my best to avoid anything to do with BCD (binary coded decimal) manipulation. Sure, it looks fun if you want to soak in the whole information pool and redo the program to turn bits rather than string numbers. Of course, the really good online precision calculators may be based on just that.; in which case the best I can do is approximate something between those apps and the ones that ignore repetends all together.

I looked up the largest repetend online. While 1 / 9973 gives a decimal repetend of 554 digits, the supposed largest is 1 / 9967, which gives a whopping 9966 decimal digits before repeating! I had to set my string math limit&& variable to 20,000 places to test it.

Working with 20,000 digits for each division calculation to catch something like this would make my calculator way too slow; about 2 to 3-seconds per non-terminating calculations.
Reply
#10
(07-31-2022, 08:57 PM)Pete Wrote: For you math folks, if you have a more elegant way to do this, I'd love to see it. Also, please excuse the message for "Eventual infinite repetend." I used this made up term to describe fractions like 1 / 6 where the digits repeat, but not immediately following the decimal point like 1 / 3 does. If you know the correct term for this type of repetend, please let me know.

Pete

There is no official name for the digits that precede the repetend.
I have seen many different terms used on various web pages about repetends such as "non-repeating digits" of the repetend and "prefix" of the repetend.

Personally,  I prefer to use "unique digit(s)" of the repetend because that's the term I thought of to best describe the non-repeating part of a repeating decimal number when I started to update a "divide" program I wrote for the TRS-80 Color Computer back in 1989 so that it could find repetends using QB4.5 a few years ago.

So, I guess the short story is that you can call the non-repeating part of a repeating decimal number anything you want to as long as it's within reason / makes sense [it properly describes the digit(s)].


----->>
I guess you have already found that for (1/x), the repetend can be almost any length BUT it will never be greater than (x-1).

(For example, 1 / 7 has a repetend of 6 digits and 1 / 65537 has a repetend of 65536 digits.)


So far as "unique digits", the most I've ever found using 1 divided by a 15 digit number is 48 : 

1 / 844,424,930,131,968 = .000000000000001184237892933500309785207112630208333333
                                        (This answer has forty-eight unique digits, and then one digit repeats infinitely.)


There can also be times when the "unique digits" might APPEAR to be the repetend but when the calculation is carried out further the true repetend appears : 

10,976.88888888888888877912 / 6 = 1,829.48148148148148146318666666666666666666666
                                                         (It looks like "481" will be the repeating pattern at first, but only one digit repeats infinitely.)


The longest TERMINATING decimal number I've found using 1 divided by 15 digits is 49 digits long : 

1 / 562,949,953,421,312 = .0000000000000017763568394002504646778106689453125
                                        (This is a 49 digit terminating decimal number.)


----->>
As soon as I can get the program cleaned up a little, I'll upload it.  I also need to edit or remove a few references to the .net and .org sites, so it will be at least a few days or more before I can get everything ready.

I'm sure you can easily make use of it to explore repetends and the number of digits required to be checked in order to find them (at least the way I do it).


NOTE :  I am not a "professional" mathematician by any means, just someone who became facinated by repeating decimal numbers way back in the 8th grade....
Reply




Users browsing this thread: 7 Guest(s)