Bernoulli numbers: Difference between revisions

m
→‎{{header|AppleScript}}: Tidy-up, more comments, minor optimisations.
(Added AppleScript.)
m (→‎{{header|AppleScript}}: Tidy-up, more comments, minor optimisations.)
Line 222:
 
=={{header|AppleScript}}==
I've onlyTo beenbe able to gethandle accurate results up to B(31) using AppleScript's number classes and operators and up to B(57) with the Foundation framework's NSDecimalNumber class in AppleScriptObjC. To handlenumbers up to B(60) and beyond, thethis script hererepresents replacesthe numbers with lists whose items are integers representing the numbers' decimaldigit digitsvalues — which of course requires custom math routines.
<lang applescript>on bernoullis(n) -- Return a list of "numerator / denominator" texts representing Bernoulli numbers B(0) to B(n).
set listMathScript to getListMathScript(10) -- Script object providing custom list math routines.
Line 228:
set output to {}
-- Akiyama–Tanigawa algorithm for the "second Bernoulli numbers".
-- List 'a' will contain {numerator, denominator} lists for therepresenting fractions.
-- The numerators and denominators will in turn be lists containing integers asrepresenting their (decimal) digits.
set a to {}
repeat with m from 0 to n
Line 236:
set a's end to result
repeat with j from m to 1 by -1
-- Retrieve the preceding fraction's numerator and denominator.
set {numerator1, denominator1} to a's item j
tell listMathScript
-- ResetGet {numerator2,the denominator2}two tofractions' (precedinglowest fractioncommon -denominator newand fraction)adjust *the jnumerators as follows:accordingly.
-- Work out the two fractions' lowest common denominator and adjust the numerators accordingly.
set lcd to its lcm(denominator1, denominator2)
set numerator1 to its multiply(numerator1, its |div|(lcd, denominator1))
set numerator2 to its multiply(numerator2, its |div|(lcd, denominator2))
-- Subtract numerator2 from numerator1 and multiply the result by j.
-- Assign the results to numerator2 and denominator2 for the next iteration.
set numerator2 to its multiply(its subtract(numerator1, numerator2), its intToList(j))
set denominator2 to lcd
end tell
-- StoreAlso thestore resulting fractionthem in a's slot j. Don'tNo botherneed to reduce itthem here.
set a's item j to {numerator2, denominator2}
end repeat
-- The fraction just stored in a's first slot is Bernoulli(m). Reduce it and append a text representation to the output.
-- Reduce it and append a text representation to the output.
tell listMathScript
set gcd to its hcf(numerator2, denominator2)
Line 266 ⟶ 265:
on getListMathScript(base)
script
on multiply(alst1, blst2) -- Multiply list alst1 by list blst2.
set aLengthlst1Length to (count alst1)
set bLengthlst2Length to (count blst2)
set productLength to aLengthlst1Length + bLengthlst2Length - 1
set product to {}
repeat productLength times
Line 275 ⟶ 274:
end repeat
-- Long multiplication algorithm, updating product digits on the fly instead of summing rows at the end.
repeat with bIndex from -1 to -bLength by -1
repeat with lst2Index from set bDigit-1 to b's-lst2Length itemby bIndex-1
ifset (bDigitlst2Digit isto notlst2's 0)item thenlst2Index
if (lst2Digit is not set0) q to q + 1then
set carry to 0
set productIndex to bIndexlst2Index
repeat with aIndexlst1Index from aLengthlst1's length to 1 by -1
settell subresult to bDigitlst2Digit * (alst1's item aIndexlst1Index) + carry + (product's item productIndex)
set product's item productIndex to (subresultit mod base)
set carry to subresult(it div base)
set segment to newSegment end tell
set productIndex to productIndex - 1
end repeat
Line 298 ⟶ 299:
end multiply
on subtract(alst1, blst2) -- Subtract list blst2 from list alst1.
set aLengthlst1Length to (count alst1)
set bLengthlst2Length to (count blst2)
copy-- aPad copies to differenceequal lengths.
copy blst1 to blst1
repeat (bLengthlst2Length - aLengthlst1Length) times
set differencelst1's beginning to 0
end repeat
repeatcopy (aLengthlst2 -to bLength) timeslst2
repeat (lst1Length - lst2Length) set b's beginning to 0times
set lst2's beginning to 0
end repeat
set-- differenceLengthIs tolst2's (countnumeric difference)value greater than lst1's?
repeatset withpaddedLength ito from 1 to(count differenceLengthlst1)
repeat with i from set aDigit1 to difference's item ipaddedLength
set bDigitlst1Digit to blst1's item i
set |b > a|lst2Digit to (bDigitlst2's >item aDigit)i
ifset ((|blst2Greater > a|) orto (aDigitlst2Digit > bDigitlst1Digit)) then exit repeat
if ((lst2Greater) or (lst1Digit > lst2Digit)) then exit repeat
end repeat
-- If so, set up to subtract lst1 from lst2 instead. We'll invert the result's sign at the end.
if (|b > a|) then set {b, difference} to {difference, b}
if (|b > a|lst2Greater) then invert(difference)tell lst2
set lst2 to lst1
set lst1 to it
end tell
set-- carryThe tosubtraction 0at last!
repeatset with i from differenceLengthdifference to 1 by -1{}
set subresultborrow to (difference's item i) - (b's item i) + carry + base0
repeat with i from set difference's item ipaddedLength to (subresult1 modby base)-1
settell carry(lst1's toitem subresulti) div+ base - 1borrow - (lst2's item i)
set difference's beginning to (it mod base)
set borrow to 1 - (it div base)
end tell
end repeat
if (carry > 0lst2Greater) then set invert(difference's beginning to carry)
if (|b > a|) then invert(difference)
return difference
end subtract
on |div|(alst1, blst2) -- List alst1 div list blst2.
return divide(alst1, blst2)'s quotient
end |div|
on |mod|(alst1, blst2) -- List alst1 mod list blst2.
return divide(alst1, blst2)'s remainder
end |mod|
on divide(alst1, blst2) -- Divide list alst1 by list blst2. Return a record containing separate lists for the quotient and remainder.
set dividend to trim(alst1)
set divisor to trim(blst2)
set dividendLength to (count dividend)
set divisorLength to (count divisor)
if (divisorLength > dividendLength) then return {quotient:{0}, remainder:adividend}
-- Note the dividend's and divisor's signs, but use absolute values in the division.
set dividendNegative to (dividend's beginning < 0)
if (dividendNegative) then invert(dividend)
Line 350 ⟶ 359:
if (divisorNegative) then invert(divisor)
-- Long-division algorithm, but quotient digits are subtraction counts.
set quotient to {}
if (divisorLength is> 1) then
set segmentremainder to {}dividend's items 1 thru (divisorLength - 1)
else
set segmentremainder to items 1 thru (divisorLength - 1) of dividend{}
end if
repeat with nextSlot from divisorLength to dividendLength
set remainder's end ofto segment todividend's item nextSlot of dividend
setrepeat qwith tosubtractionCount from 0 to base -- Only ever reaches base - 1.
repeat set subtractionResult to trim(subtract(remainder, divisor))
setif newSegment(subtractionResult's tobeginning trim(subtract(segment,< divisor)0) then exit repeat
ifset (newSegment'sremainder beginningto < 0) then exit repeatsubtractionResult
set q to q + 1
set segment to newSegment
end repeat
set end of quotient to qsubtractionCount
end repeat
-- The quotient's negative if the input signs are different. OtherwisePositive positiveotherwise.
if (dividendNegative ≠ divisorNegative) then invert(quotient)
-- The remainder's signhas isthe alwayssame sign thatas ofthe dividend.
if (dividendNegative) then invert(segmentremainder)
return {quotient:quotient, remainder:segmentremainder}
end divide
on lcm(alst1, blst2) -- Lowest common multiple of list alst1 and list blst2.
return multiply(blst2, |div|(alst1, hcf(alst1, blst2)))
end lcm
on hcf(alst1, blst2) -- Highest common factor of list alst1 and list blst2.
set alst1 to trim(alst1)
set blst2 to trim(blst2)
repeat until (blst2 = {0})
set x to alst1
set alst1 to blst2
set blst2 to trim(|mod|(x, blst2))
end repeat
if (alst1's beginning < 0) then invert(alst1)
return alst1
end hcf
Line 398 ⟶ 406:
end invert
on trim(lst) -- Return a copy of the input listlst with no leading zeros..
repeat with i from 1 to (count lst)
if (lst's item i is not 0) then exit repeat
Line 444 ⟶ 452:
set output to {""}
set padding to " = "
set bernoulliNumbers to bernoullis(maxN) -- Get all the results in one sweep.
repeat with n from 0 to maxN
set bernie to bernoulliNumbers's item (n + 1)
557

edits