I have the following code:
function recursion(i::BigFloat)
r = BigFloat(0)
if i >= 1.0
i = i - 1.0
r = 1.0/(2.0+recursion(i))
end
return r
end
function main()
solution = 0
i = BigFloat(1)
while i < 1000
sum = 1 + recursion(i)
print("\nsum: ",rationalize(sum))
if length(digits(numerator(rationalize(sum)))) > length(digits(denominator(rationalize(sum))))
solution = solution + 1
print(" <------- found")
end
i = i + 1.0
end
return solution
end
solution = main()
The goal is to find expansions of the sqrt(two) using the following equation:
(image taken from "Square Root of 2" wikipedia page)
where the rational representation has a numerator with a number of digits greater than the denominator's number of digits.
My code's logic seems to be working, however there is an upper limit where it seems to be breaking the rationalize() function when using a BigFloat type.
sum: 3//2
sum: 7//5
sum: 17//12
sum: 41//29
sum: 99//70
sum: 239//169
sum: 577//408
sum: 1393//985 <------- found
sum: 3363//2378
sum: 8119//5741
sum: 19601//13860
sum: 47321//33461
sum: 114243//80782 <------- found
sum: 275807//195025
sum: 665857//470832
sum: 1607521//1136689
sum: 3880899//2744210
sum: 9369319//6625109
sum: 22619537//15994428
sum: 54608393//38613965
sum: 131836323//93222358 <------- found
sum: 318281039//225058681
sum: 768398401//543339720
sum: 1855077841//1311738121
sum: 4478554083//3166815962
sum: 10812186007//7645370045 <------- found
sum: 26102926097//18457556052
sum: 63018038201//44560482149
sum: 152139002499//107578520350
sum: 367296043199//259717522849
sum: 886731088897//627013566048
sum: 2140758220993//1513744654945
sum: 5168247530883//3654502875938
sum: 12477253282759//8822750406821 <------- found
sum: 30122754096401//21300003689580
sum: 72722761475561//51422757785981
sum: 175568277047523//124145519261542
sum: 423859315570607//299713796309065
sum: 1023286908188737//723573111879672 <------- found
sum: 2470433131948081//1746860020068409
sum: 5964153172084899//4217293152016490
sum: 14398739476117879//10181446324101389
sum: 34761632124320657//24580185800219268
sum: 83922003724759193//59341817924539925
sum: 202605639573839043//143263821649299118
sum: 489133282872437279//345869461223138161
sum: 1180872205318713601//835002744095575440 <------- found
sum: 2850877693509864481//2015874949414289041
sum: 6882627592338442563//4866752642924153522
sum: 6882627592338442563//4866752642924153522
sum: 6882627592338442563//4866752642924153522
sum: 6882627592338442563//4866752642924153522
sum: 6882627592338442563//4866752642924153522
sum: 6882627592338442563//4866752642924153522
sum: 6882627592338442563//4866752642924153522
sum: 6882627592338442563//4866752642924153522
sum: 6882627592338442563//4866752642924153522
sum: 6882627592338442563//4866752642924153522
sum: 6882627592338442563//4866752642924153522
It gets "stuck" at the fraction 6882627592338442563//4866752642924153522. Presumably because there is some sort of upper limit within the rationalize function.
Why is it getting stuck here and how can I circumvent the problem?
There are a few issues here, all dealing with making sure that you're using types that can get as accurate or as large as you want.
First, you need to break the habit of putting decimals in your exact numbers — as in 1.0 and 2.0, which are interpreted as literal Float64s. That's fine when you're only ever dealing with 64-bit floats, but you don't want to do algebra with a Float64 and a BigFloat. In this case, since your floats are exact integers, just use the integers 1 and 2, and Julia will promote properly to BigFloat. For things that aren't exact integers, you can explicitly give literal Rationals, and the compiler will convert them to the appropriate type efficiently. Or you can explicitly convert to the number type you need, as in sqrt(big(2)) — though usually it's better to detect the input type and then do something like sqrt(T(2)). Unlike in — say, C++ — if you enter 1/2, you'll get 0.5 as a Float64. On the other hand, 1/(2+recursion(i)) will first convert 2+recursion(i) to the appropriate BigFloat, and then take the true inverse.
Second, if you look at the docstring for rationalize, you see that it has an optional argument of the type, which defaults to Int. This means the result must have numerator and denominator of this type. But Int64 can only represent numbers up to typemax(Int64), which is 9223372036854775807. And your "stuck" numerator is ~75% as large, so you probably just can't get much larger. Instead of using the default, just call it as rationalize(BigInt, sum), and you'll be able to get much larger numbers on top and bottom.
Third, note the third argument of rationalize, which says that it will stop trying to find a better approximation once the result is within tol, which defaults to the machine precision of the input. For sqrt(big(2)), that's about 1.7e-77. So rationalize won't give you anything more once the result is within that distance of sqrt(big(2)). So even with Big*, you're results will get "stuck" eventually.
Anyway, putting that all together:
function recursion(i::BigFloat)
r = BigFloat(0)
if i >= 1
i = i - 1
r = 1/(2+recursion(i))
end
return r
end
function main()
solution = 0
i = BigFloat(1)
while i < 1000
sum = 1 + recursion(i)
ratio = rationalize(BigInt, sum)
print("\nsum: ",ratio)
if length(digits(numerator(ratio))) > length(digits(denominator(ratio)))
solution = solution + 1
print(" <------- found")
end
i = i + 1
end
return solution
end
solution = main()
And the result looks like
sum: 3//2
sum: 7//5
sum: 17//12
sum: 41//29
sum: 99//70
sum: 239//169
sum: 577//408
sum: 1393//985 <------- found
sum: 3363//2378
sum: 8119//5741
sum: 19601//13860
sum: 47321//33461
sum: 114243//80782 <------- found
sum: 275807//195025
sum: 665857//470832
sum: 1607521//1136689
sum: 3880899//2744210
sum: 9369319//6625109
sum: 22619537//15994428
sum: 54608393//38613965
sum: 131836323//93222358 <------- found
sum: 318281039//225058681
sum: 768398401//543339720
sum: 1855077841//1311738121
sum: 4478554083//3166815962
sum: 10812186007//7645370045 <------- found
sum: 26102926097//18457556052
sum: 63018038201//44560482149
sum: 152139002499//107578520350
sum: 367296043199//259717522849
sum: 886731088897//627013566048
sum: 2140758220993//1513744654945
sum: 5168247530883//3654502875938
sum: 12477253282759//8822750406821 <------- found
sum: 30122754096401//21300003689580
sum: 72722761475561//51422757785981
sum: 175568277047523//124145519261542
sum: 423859315570607//299713796309065
sum: 1023286908188737//723573111879672 <------- found
sum: 2470433131948081//1746860020068409
sum: 5964153172084899//4217293152016490
sum: 14398739476117879//10181446324101389
sum: 34761632124320657//24580185800219268
sum: 83922003724759193//59341817924539925
sum: 202605639573839043//143263821649299118
sum: 489133282872437279//345869461223138161
sum: 1180872205318713601//835002744095575440 <------- found
sum: 2850877693509864481//2015874949414289041
sum: 6882627592338442563//4866752642924153522
sum: 16616132878186749607//11749380235262596085
sum: 40114893348711941777//28365513113449345692
sum: 96845919575610633161//68480406462161287469
sum: 233806732499933208099//165326326037771920630
sum: 564459384575477049359//399133058537705128729
sum: 1362725501650887306817//963592443113182178088 <------- found
sum: 3289910387877251662993//2326317944764069484905
sum: 7942546277405390632803//5616228332641321147898
sum: 19175002942688032928599//13558774610046711780701
sum: 46292552162781456490001//32733777552734744709300
sum: 111760107268250945908601//79026329715516201199301 <------- found
sum: 269812766699283348307203//190786436983767147107902
sum: 651385640666817642523007//460599203683050495415105
sum: 1572584048032918633353217//1111984844349868137938112
sum: 3796553736732654909229441//2684568892382786771291329
sum: 9165691521498228451812099//6481122629115441680520770
sum: 22127936779729111812853639//15646814150613670132332869
sum: 53421565080956452077519377//37774750930342781945186508
sum: 128971066941642015967892393//91196316011299234022705885 <------- found
sum: 311363698964240484013304163//220167382952941249990598278
sum: 751698464870122983994500719//531531081917181734003902441
sum: 1814760628704486452002305601//1283229546787304717998403160
sum: 4381219722279095887999111921//3097990175491791170000708761
sum: 10577200073262678228000529443//7479209897770887057999820682 <------- found
sum: 25535619868804452344000170807//18056409971033565286000350125
sum: 61648439810871582916000871057//43592029839838017630000520932
sum: 148832499490547618176001912921//105240469650709600546001391989
sum: 359313438791966819268004696899//254072969141257218722003304910
sum: 867459377074481256712011306719//613386407933224037990008001809
sum: 2094232192940929332692027310337//1480845785007705294702019308528
sum: 5055923762956339922096065927393//3575077977948634627394046618865
sum: 12206079718853609176884159165123//8631001740904974549490112546258 <------- found
sum: 29468083200663558275864384257639//20837081459758583726374271711381
sum: 71142246120180725728612927680401//50305164660422142002238655969020
sum: 171752575441025009733090239618441//121447410780602867730851583649421
sum: 414647397002230745194793406917283//293199986221627877463941823267862
sum: 1001047369445486500122677053453007//707847383223858622658735230185145 <------- found
sum: 2416742135893203745440147513823297//1708894752669345122781412283638152
sum: 5834531641231893991002972081099601//4125636888562548868221559797461449
sum: 14085805418356991727446091676022499//9960168529794442859224531878561050 <------- found
sum: 34006142477945877445895155433144599//24045973948151434586670623554583549
sum: 82098090374248746619236402542311697//58052116426097312032565778987728148
sum: 198202323226443370684367960517767993//140150206800346058651802181530039845
sum: 478502736827135487987972323577847683//338352530026789429336170142047807838
sum: 1155207796880714346660312607673463359//816855266853924917324142465625655521 <------- found
sum: 2788918330588564181308597538924774401//1972063063734639263984455073299118880
sum: 6733044458057842709277507685523012161//4760981394323203445293052612223893281
sum: 16255007246704249599863612909970798723//11494025852381046154570560297746905442
sum: 39243058951466341909004733505464609607//27749033099085295754434173207717704165
sum: 94741125149636933417873079920900017937//66992092050551637663438906713182313772
sum: 228725309250740208744750893347264645481//161733217200188571081311986634082331709
sum: 323466434400377142162623973268164663418//228725309250740208744750893347264645481
sum: 228725309250740208744750893347264645481//161733217200188571081311986634082331709
sum: 228725309250740208744750893347264645481//161733217200188571081311986634082331709
sum: 228725309250740208744750893347264645481//161733217200188571081311986634082331709
sum: 228725309250740208744750893347264645481//161733217200188571081311986634082331709
sum: 228725309250740208744750893347264645481//161733217200188571081311986634082331709
sum: 228725309250740208744750893347264645481//161733217200188571081311986634082331709
sum: 228725309250740208744750893347264645481//161733217200188571081311986634082331709
sum: 228725309250740208744750893347264645481//161733217200188571081311986634082331709
sum: 228725309250740208744750893347264645481//161733217200188571081311986634082331709
sum: 228725309250740208744750893347264645481//161733217200188571081311986634082331709
sum: 228725309250740208744750893347264645481//161733217200188571081311986634082331709
sum: 228725309250740208744750893347264645481//161733217200188571081311986634082331709
sum: 228725309250740208744750893347264645481//161733217200188571081311986634082331709
So it does get "stuck", but just evaluate that final result compared to sqrt(big(2)), and you should be pretty happy.
Mike asked in another answer what the convergence of this algorithm looks like when precision is set to a high value.
The answer is that it looks just about perfectly steady. The residual decreases by roughly a factor of sqrt(2) each iteration. Here is the log of the residual versus iteration:
Related
with the rec sum:
let rec sum a=if a==0 then 0 else a+sum(a-1)
if the compiler use the tail recursive optimization,it may create a variable "sum" to iteration(when I use the "ocamlc -dlambda",the recursive still there.when I use "ocamlc -dinstr" got the assemably code,I can't read it now)
but on the book《Design Concepts of programming languages》,page 287,it can change the function to this(the key line):n*(n+1)/2
"You should convince yourself that the least fixed point of this
function is the computation csum that returns a summation procedure that,returns n*(n+1)/2 if its argument is a nonnegative integer in"
I can't understand it,the prog not Gauss!I think it can't chang the "rec sum" to n*(n+1)/2 automatic!only man can do it,right?
So how this book write here means?Is anyone know?Thanks!
I believe your book is merely making a small point about equivalence of pure functions. Nevertheless, optimising away a loop that only contains affine operations is relatively easy.
Equivalence of pure functions
I haven't read that book, but from the paragraph you quote, I think the book merely makes a point about pure functions. Since sum is a pure function, i.e. a function without side-effect, then in a sense,
let rec sum n =
if n = 0 then 0
else n + sum (n - 1)
is equivalent to
let sum n =
n * (n + 1) / 2
But of course "equivalent" here ignores the time and space complexity, and unless the compiler has some sort of hardcoding for common functions to optimise, I'd be extremely surprised if it optimised sum like that.
Also note that the two above functions are only equivalent so far as they are only called on a nonnegative argument. The recursive version will loop infinitely (and provoke a stack overflow) if n is negative; the direct formula version will always return a result, although that result will be nonsensical if n is negative.
Optimising loops that only contain affine operations
Nevertheless, writing a compiler that would perform such optimisations is not complete science-fiction. At the end of this answer you will find links to two blogposts which you might be interested in. In this answer I will summarise how the method described in those blog posts can be applied to your problem.
First let's rewrite function sum as a loop in pseudo-code:
function sum(n):
s := 0
i := 1
repeat n:
s += i
i += 1
return s
This kind of rewriting is similar to what happens when sum is transformed into a tail-recursive function.
Now if you consider the vector v = [s, i, 1], then the affine operations s += i and i += 1 can be described as multiplying v by a matrix:
s += i
[[ 1, 0, 0 ], # matrix Msi
[ 1, 1, 0 ],
[ 0, 0, 1 ]]
i += 1
[[ 1, 0, 0 ], # matrix Mi1
[ 0, 1, 0 ],
[ 0, 1, 1 ]]
s += i, i += 1
[[ 1, 0, 0 ], # M = Msi * Mi1
[ 1, 1, 0 ],
[ 0, 1, 1 ]]
This affine operation is wrapped in a "repeat n" loop. So we have to multiply v by this matrix M, n times. But matrix multiplication is associative; so instead of doing n multiplications by matrix M, we can raise matrix M to its nth power, and then multiply v by the resulting matrix M**n.
As it turns out:
[[1, 0, 0], [[ 1, 0, 0],
[1, 1, 0], to the nth = [ n, 1, 0],
[0, 1, 1]] [n*(n - 1)/2, n, 1]]
which represents the affine operation:
s = s + n * i + n * (n - 1) / 2
i = i + n
Starting from s, i = 0, 1, this gives us s = n * (n+1) / 2 as expected.
More reading:
Using the Quick Raise of Matrices to a Power to Write a Very Fast Interpreter of a Simple Programming Language;
Automatic Algorithms Optimization via Fast Matrix Exponentiation.
find key : sum in nested map and update its value to : bill * 100 + : coins
Need to pass test1
test "test1" do
assert BcToInt.data(%{
count: 3,
sum: %{bills: 1, coins: 99},
tax: %{count: 3, sum: %{bills: 1, coins: 1}}
}) ==
%{count: 3, sum: 199, tax: %{count: 3, sum: 101}}
end
I tried to do it using Map_replace() and checking value for nested map using is_map and call function again if true but how to get end result
def data(xmap) do
Enum.map(xmap, fn {_key, value} ->
keyy = :sum
aa = List.first(Map.values(xmap[keyy])) * 100 + List.last(Map.values(xmap[keyy]))
if Map.has_key?(xmap, keyy) do
Map.replace(xmap, keyy, aa)
if is_map(value) do
data1(value)
end
end
end)
end
Here's a version without using external libraries:
def data(map) do
map =
case map[:sum] do
%{bills: bills, coins: coins} -> %{map | sum: bills * 100 + coins}
_ -> map
end
Map.new(map, fn
{k, v} when is_map(v) -> {k, data(v)}
entry -> entry
end)
end
Usage:
iex(1)> data = ...
%{
count: 3,
sum: %{bills: 1, coins: 99},
tax: %{count: 3, sum: %{bills: 1, coins: 1}}
}
iex(2)> BcToInt.data(data)
%{count: 3, sum: 199, tax: %{count: 3, sum: 101}}
With a help of iteraptor library:
Mix.install([:iteraptor])
Iteraptor.map(data, fn
{_k, %{bills: bills, coins: coins}} -> bills * 100 + coins
# Is not `bill:` a typo?
{_k, %{bill: bills, coins: coins}} -> bills * 100 + coins
other -> other
end, yield: :all)
#⇒ %{count: 3, sum: 199, tax: %{count: 3, sum: 101}}
Your implementation correctly uses recursion to look into nested data structures. It looks like it's trying to use Map.replace/3 to try to modify the data structure in place, though. Elixir only has immutable data structures, so you need to construct a new map from the input rather than trying to update it in place.
I might implement the recursion here using pattern matching:
def data(%{bills: bills, coins: coins}) do
bills * 100 + coins
end
def data(map) when is_map(map) do
Map.new(map, fn {k, v} -> {k, data(v)} end)
end
def data(any) do
any
end
With this setup, if data/1 is called with a map with the :bills and :coins keys (not necessarily in a field named :sum) it adds them together; on any other map, it recurses through the values preserving the keys; and on any other value it returns the original value as-is.
def data(xmap) do
keyy = :sum
aa = List.first(Map.values(xmap[keyy])) * 100 +
List.last(Map.values(xmap[keyy]))
Map.new(xmap, fn
{k, _v} when k == keyy -> {k, aa}
{k, v} when is_map(v) -> {k, data(v)}
{k, v} -> {k, v}
end)
end
I am trying to build a function to factorize a number. in this example I used the number 95 and a list of prime numbers. The result should be (5, 19). What am I doing wrong?
function factorize(number, primes)
global factor = Int64[]
for i in primes
while number % primes[i] == 0
push!(factor, primes[i])
number = number ÷ primes[i]
end
if number ÷ primes[i] != 1
break
end
end
return factor
end
number = 95
primes = (2,3,5,7,11,13,17,19,23, 27, 31)
answer = factorize(number, primes)
println(answer)
This is a fixed function:
function factorize(number, primes)
factor = Int64[]
for p in primes
while number % p == 0
push!(factor, p)
number = number ÷ p
end
if number == 1
break
end
end
if number > 1
#warn "factorization failed, not enough primes passed; printing only factors found in primes vector"
end
return factor
end
Changes:
you do not need global qualifier
writing p in primes returns you the elements of primes not the index into primes
the termination condition should be number == 1
error handling if primes vector does not contain all primes that are required
Note that you can compare your results with function factor from Primes.jl package (but I guess you wanted this code as an algorithmic problem).
I have a odd number n and want to use (n+1)/2 as an array index. What is the best way to calculate the index? I just came up with to use Int((n+1)/2), round(Int, (n+1)/2)) and Int((n+1)//2). Which is better or don't I need to too worry about them?
For better performance, you need integer division (div or ÷) for that. / gives floating point results for integer arguments. // gives a Rational not an integer. So you need to write div(n+1, 2) or (n+1) ÷ 2. To type ÷ you can write \div and then press TAB on julia REPL, Jupyter notebook, Atom, etc.
Even if the dividend (n+1) is even, you need integer division to obtain an integer result directly, otherwise you need to convert the result to integer which will in turn be costly compared to the integer division.
You may also use right bit shift operator >> or unsigned right bit shift operator >>>, as positive integer division by 2^n corresponds to shifting bits of that integer to the right n times. Although integer division by a power of 2 will be lowered to bit shift operation(s) by the compiler, the compiled code will still have an extra step if the dividend is a signed integer (i.e. Int and not UInt). Therefore, using the right bit shift operators instead may give better performance, although this is likely to be a premature optimization and affects the readability of your code.
The results of >> and >>> with negative integers will be different than that of the integer division (div).
Also note that using unsigned right bit shift operator >>> might save you from some integer overflow issues.
div(x, y)
÷(x, y)
The quotient from Euclidean division. Computes x/y, truncated to an
integer.
julia> 3/2 # returns a floating point number
1.5
julia> julia> 4/2
2.0
julia> 3//2 # returns a Rational
3//2
# now integer divison
julia> div(3, 2) # returns an integer
1
julia> 3 ÷ 2 # this is the same as div(3, 2)
1
julia> 9 >> 1 # this divides a positive integer by 2
4
julia> 9 >>> 1 # this also divides a positive integer by 2
4
# results with negative numbers
julia> -5 ÷ 2
-2
julia> -5 >> 1
-3
julia> -5 >>> 1
9223372036854775805
# results with overflowing (wrapping-around) argument
julia> (Int8(127) + Int8(3)) ÷ 2 # 127 is the largest Int8 integer
-63
julia> (Int8(127) + Int8(3)) >> 1
-63
julia> (Int8(127) + Int8(3)) >>> 1 # still gives 65 (130 ÷ 2)
65
You can use #code_native macro to see how things are compiled to native code. Please do not forget more instructions does not necessarily imply being slower, although here it is be the case.
julia> f(a) = a ÷ 2
f (generic function with 2 methods)
julia> g(a) = a >> 1
g (generic function with 2 methods)
julia> h(a) = a >>> 1
h (generic function with 1 method)
julia> #code_native f(5)
.text
; Function f {
; Location: REPL[61]:1
; Function div; {
; Location: REPL[61]:1
movq %rdi, %rax
shrq $63, %rax
leaq (%rax,%rdi), %rax
sarq %rax
;}
retq
nop
;}
julia> #code_native g(5)
.text
; Function g {
; Location: REPL[62]:1
; Function >>; {
; Location: int.jl:448
; Function >>; {
; Location: REPL[62]:1
sarq %rdi
;}}
movq %rdi, %rax
retq
nopw (%rax,%rax)
;}
julia> #code_native h(5)
.text
; Function h {
; Location: REPL[63]:1
; Function >>>; {
; Location: int.jl:452
; Function >>>; {
; Location: REPL[63]:1
shrq %rdi
;}}
movq %rdi, %rax
retq
nopw (%rax,%rax)
;}
In pandas, there is the clip function (see https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.clip.html), which constrains values within the lower and upper bound provided by the user. What is the Julia equivalent? I.e., I would like to have:
> clip.([2 3 5 10],3,5)
> [3 3 5 5]
Obviously, I can write it myself, or use a combination of min and max, but I was surprised to find out there is none. StatsBase provides the trim and winsor functions, but these do not allow fixed values as input, but rather counts or percentiles (https://juliastats.github.io/StatsBase.jl/stable/robust.html).
You are probably looking for clamp:
help?> clamp
clamp(x, lo, hi)
Return x if lo <= x <= hi. If x > hi, return hi. If x < lo, return lo. Arguments are promoted to a common type.
This is a function for scalar x, but we can broadcast it over the vector using dot-notation:
julia> clamp.([2, 3, 5, 10], 3, 5)
4-element Array{Int64,1}:
3
3
5
5
If you don't care about the original array you can also use the in-place version clamp!, which modifies the input:
julia> A = [2, 3, 5, 10];
julia> clamp!(A, 3, 5);
julia> A
4-element Array{Int64,1}:
3
3
5
5