I'm summing a long list of Ratios in Clojure, something like:
(defn sum-ratios
[n]
(reduce
(fn [total ind]
(+
total
(/
(inc (rand-int 100))
(inc (rand-int 100)))))
(range 0 n)))
The runtime for various n is:
n = 10^4 ...... 41 ms
n = 10^6 ...... 3.4 s
n = 10^7 ...... 36 s
The (less precise) alternative is to sum these values as doubles:
(defn sum-doubles
[n]
(reduce
(fn [total ind]
(+
total
(double
(/
(inc (rand-int 100))
(inc (rand-int 100))))))
(range 0 n)))
The runtime for this version is:
n = 10^4 ...... 8.8 ms
n = 10^6 ...... 350 ms
n = 10^7 ...... 3.4 s
Why is it significantly slower to sum Ratios? I'm guessing that it has to do with finding the least common multiple of the denominators of the Ratios being summed, but does anybody know specifically which algorithm Clojure uses to sum Ratios?
Let's follow what happens when you + two Ratios, which is what happens at each step in the reduction. We start at the two-arity version of +:
([x y] (. clojure.lang.Numbers (add x y)))
This takes us to Numbers.add(Obj, Obj):
return ops(x).combine(ops(y)).add((Number)x, (Number)y);
ops looks at the class of the first operand and will find RatioOps. This leads to the RatioOps.add function:
final public Number add(Number x, Number y){
Ratio rx = toRatio(x);
Ratio ry = toRatio(y);
Number ret = divide(ry.numerator.multiply(rx.denominator)
.add(rx.numerator.multiply(ry.denominator))
, ry.denominator.multiply(rx.denominator));
return normalizeRet(ret, x, y);
}
So here's your algorithm. There are five BigInteger operations here (three multiplies, one add, one divide):
(yn*xd + xn*yd) / (xd*yd)
You can see how multiply is implemented; it alone is not trivial, and you can examine the others for yourself.
Sure enough, the divide function involves finding the gcd between the two numbers so it can be reduced:
static public Number divide(BigInteger n, BigInteger d){
if(d.equals(BigInteger.ZERO))
throw new ArithmeticException("Divide by zero");
BigInteger gcd = n.gcd(d);
if(gcd.equals(BigInteger.ZERO))
return BigInt.ZERO;
n = n.divide(gcd);
d = d.divide(gcd);
...
}
The gcd function creates two new MutableBigInteger objects.
Computationally, it's expensive, as you can see from all of the above. However, don't discount the cost of extra incidental object creation (as in gcd above), as that is often more expensive as we involve non-cached memory access.
The double conversion is not free, FWIW, as it involves a division of two newly-created BigDecimals.
You really need a profiler to see exactly where the cost is. But hopefully the above gives a little context.
Related
My professor has given me an RSA factoring problem has assignment. The given modulus is 30 decimal digits long. I have been searching a lot about factoring algorithms. But it has been quite a headache to choose one for my given requirements. Which all algorithms give better performance for 30 decimal digit numbers?
Note: So far I have read about Brute force approach and Quadratic Sieve. The latter is complex and the former time consuming.
There's another method called Pollard's Rho algorithm, which is not as fast as the GNFS but is capable of factoring 30-digit numbers in minutes rather than hours.
The algorithm is very simple. It stops when it finds any factor, so you'll need to call it recursively to obtain a complete factorisation. Here's a basic implementation in Python:
def rho(n):
def gcd(a, b):
while b > 0:
a, b = b, a%b
return a
g = lambda z: (z**2 + 1) % n
x, y, d = 2, 2, 1
while d == 1:
x = g(x)
y = g(g(y))
d = gcd(abs(x-y), n)
if d == n:
print("Can't factor this, sorry.")
print("Try a different polynomial for g(), maybe?")
else:
print("%d = %d * %d" % (n, d, n // d))
rho(441693463910910230162813378557) # = 763728550191017 * 578338290221621
Or you could just use an existing software library. I can't see much point in reinventing this particular wheel.
void func(int n){
int i=1, k=n;
while (i<=k){
k=k/2;
i = i*2;
}
}
How do i calculate the time complexity of this function? I understand that the assignment of i=1, k=n takes two basic steps and to divide the value of k and multiply the value of i takes two basic steps as well, but because the values of i and k are increasing and decreasing exponentially, will the time complexity be O(log base 4 N) or O(log base 2 sqrt(N))?
Your answer is O(log √n), in the comments #Eraklon says it's O((log2 n)/2), and #matri70boss says it's O(log4 n). All three of you are correct, but the answer in its simplest form is O(log n).
log √n = log n0.5 = 0.5 log n, and we discard the constant factor 0.5 when we write in big O notation.
(log2 n)/2 = (log n)/(2 log 2) by the change of base identity, and 1/(2 log 2) is another constant factor we can discard.
Likewise, log4 n = (log n)/(log 4), and we can discard the constant factor 1/(log 4).
I'm trying to do a function who implements a sum of n cubes:
1^3 + 2^3 + 3^3 + ... + n^3 = sum
My function should receive a sum and return a n or -1 if n doesn't exists.
Some examples:
(find-n 9) ; should return 2 because 1^3 + 2^3 = 9
(find-n 100) ; should return 4 because 1^3 + 2^3 + 3^3 + 4^3 = 100
(find-n 10) ; should return -1
After some work I made these two functions:
; aux function
(defn exp-3 [base] (apply *' (take 3 (repeat base))))
; main function
(defn find-n [m]
(loop [sum 0
actual-base 0]
(if (= sum m)
actual-base
(if (> sum m)
-1
(recur (+' sum (exp-3 (inc actual-base))) (inc actual-base))))))
These functions are working properly but is taking too long to evaluate operations with BigNumbers, as example:
(def sum 1025247423603083074023000250000N)
(time (find-n sum))
; => "Elapsed time: 42655.138544 msecs"
; => 45001000
I'm asking this question to raise some advices of how can I make this function faster.
This is all about algebra, and little to do with Clojure or programming. Since this site does not support mathematical typography, let's express it in Clojure.
Define
(defn sigma [coll] (reduce + coll))
and
(defn sigma-1-to-n [f n]
(sigma (map f (rest (range (inc n))))))
(or
(defn sigma-1-to-n [f n]
(->> n inc range rest (map f) sigma))
)
Then the question is, given n, to find i such that (= (sigma-1-to-n #(* % % %) i) n).
The key to doing this quickly is Faulhaber's formula for cubes. It tells us that the following are equal, for any natural number i:
(#(*' % %) (sigma-1-to-n identity i))
(sigma-1-to-n #(* % % %) i)
(#(*' % %) (/ (*' i (inc i)) 2))
So, to be the sum of cubes, the number
must be a perfect square
whose square root is the sum of the first so many numbers.
To find out whether a whole number is a perfect square, we take its approximate floating-point square root, and see whether squaring the nearest integer recovers our whole number:
(defn perfect-square-root [n]
(let [candidate (-> n double Math/sqrt Math/round)]
(when (= (*' candidate candidate) n)
candidate)))
This returns nil if the argument is not a perfect square.
Now that we have the square root, we have to determine whether it is the sum of a range of natural numbers: in ordinary algebra, is it (j (j + 1)) / 2, for some natural number j.
We can use a similar trick to answer this question directly.
j (j + 1) = (j + 1/2)^2 + 1/4
So the following function returns the number of successive numbers that add up to the argument, if there is one:
(defn perfect-sum-of [n]
(let [j (-> n (*' 2)
(- 1/4)
double
Math/sqrt
(- 0.5)
Math/round)]
(when (= (/ (*' j (inc j)) 2) n)
j)))
We can combine these to do what you want:
(defn find-n [big-i]
{:pre [(integer? big-i) ((complement neg?) big-i)]}
(let [sqrt (perfect-square-root big-i)]
(and sqrt (perfect-sum-of sqrt))))
(def sum 1025247423603083074023000250000N)
(time (find-n sum))
"Elapsed time: 0.043095 msecs"
=> 45001000
(Notice that the time is about twenty times faster than before, probably because HotSpot has got to work on find-n, which has been thoroughly exercised by the appended testing)
This is obviously a lot faster than the original.
Caveat
I was concerned that the above procedure might produce false negatives (it will never produce a false positive) on account of the finite precision of floating point. However, testing suggests that the procedure is unbreakable for the sort of number the question uses.
A Java double has 52 bits of precision, roughly 15.6 decimal places. The concern is that with numbers much bigger than this, the procedure may miss the exact integer solution, as the rounding can only be as accurate as the floating point number that it starts with.
However, the procedure solves the example of a 31 digit integer correctly. And testing with many (ten million!) similar numbers produces not one failure.
To test the solution, we generate a (lazy) sequence of [limit cube-sum] pairs:
(defn generator [limit cube-sum]
(iterate
(fn [[l cs]]
(let [l (inc l)
cs (+' cs (*' l l l))]
[limit cs]))
[limit cube-sum]))
For example,
(take 10 (generator 0 0))
=> ([0 0] [1 1] [2 9] [3 36] [4 100] [5 225] [6 441] [7 784] [8 1296] [9 2025])
Now we
start with the given example,
try the next ten million cases and
remove the ones that work.
So
(remove (fn [[l cs]] (= (find-n cs) l)) (take 10000000 (generator 45001000 1025247423603083074023000250000N)))
=> ()
They all work. No failures. Just to make sure our test is valid:
(remove (fn [[l cs]] (= (find-n cs) l)) (take 10 (generator 45001001 1025247423603083074023000250000N)))
=>
([45001001 1025247423603083074023000250000N]
[45001002 1025247514734170359564546262008N]
[45001003 1025247605865263720376770289035N]
[45001004 1025247696996363156459942337099N]
[45001005 1025247788127468667814332412224N]
[45001006 1025247879258580254440210520440N]
[45001007 1025247970389697916337846667783N]
[45001008 1025248061520821653507510860295N]
[45001009 1025248152651951465949473104024N]
[45001010 1025248243783087353664003405024N])
All ought to fail, and they do.
Just avoiding the apply (not really all that fast in CLJ) gives you a 4x speedup:
(defn exp-3 [base]
(*' base base base))
And another 10%:
(defn find-n [m]
(loop [sum 0
actual-base 0]
(if (>= sum m)
(if (= sum m) actual-base -1)
(let [nb (inc actual-base)]
(recur (+' sum (*' nb nb nb)) nb)))))
The following algorithmic-based approach relies on one simple formula which says that the sum of the cubes of the first N natural numbers is: (N*(N+1)/2)^2
(defn sum-of-cube
"(n*(n+1)/2)^2"
[n]
(let [n' (/ (*' n (inc n)) 2)]
(*' n' n')))
(defn find-nth-cube
[n]
((fn [start end prev]
(let [avg (bigint (/ (+' start end) 2))
cube (sum-of-cube avg)]
(cond (== cube n) avg
(== cube prev) -1
(> cube n) (recur start avg cube)
(< cube n) (recur avg end cube))))
1 n -1))
(time (find-nth-cube 1025247423603083074023000250000N))
"Elapsed time: 0.355177 msecs"
=> 45001000N
We want to find the number N such that the sum of 1..N cubes is some number X. To find if such a number exists, we can perform a binary search over some range for it by applying the above formula to see whether the result of the formula equals X. This approach works because the function at the top is increasing, and thus any value f(n) which is too large means that we must look for a lower number n, and any value f(n) which is too small means that we must look for a larger number n.
We choose a (larger than necessary, but easy and safe) range of 0 to X. We will know that the number exists if our formula applied to a given candidate number yields X. If it does not, we continue the binary search until either we find the number, or until we have tried the same number twice, which indicates that the number does not exist.
With an upper bound of logN, only takes 1 millisecond to compute 1E100 (1 googol), so it's very efficient for an algorithmic approach.
You may want to use some mathematical tricks.
(a-k)^3 + (a+k)^3 = 2a^3+(6k^2)a
So, a sum like:
(a-4)^3+(a-3)^3+(a-2)^3+(a-1)^3+a^3+(a+1)^3+(a+2)^3+(a+3)^3+(a+4)^3
= 9a^3+180a
(please confirm correctness of the calculation).
Using this equation, instead of incrementing by 1 every time, you can jump by 9 (or by any 2 k+1 you like). You can check for the exact number whenever you hit a bigger number than n.
Other way to improve is to have a table of ns and sums, by making a batch of computations once and use this table later in function find-n.
I am currently learning LISP by going through some of the problems on ProjectEuler site. One of the problems asks this:
The prime factors of 13195 are 5, 7, 13 and 29.
What is the largest prime factor of the number 600851475143 ?
I have scrapped together Lisp code that does this. However, for numbers with 9+ digits, it is very slow. Most of the time I never get a solution, whereas for 8 digits, it takes about 4-5 seconds. What's more, sometimes I get "HEAP exceeded" error.
My question is am I doing something wrong in terms of running the code (use Aquamacs)? What are some ways this code can be optimized to be better suited for the task at hand? More importantly, how can "exceeded HEAP" crashes be avoided?
Code:
(defun potential-factors (number)
(loop for x from 1 to (ceiling (/ number 2))
for y = x
collect y))
(defun factors (number)
(let (prime-factors '())
(loop for x in (potential-factors number)
do (if (= (mod number x) 0)
(setq prime-factors (cons x prime-factors))))
prime-factors))
(defun is-prime (n &optional (d (- n 1)))
(if (/= n 1)
(or (= d 1)
(and (/= (rem n d) 0)
(is-prime n (- d 1)))) ()))
(defun problem-3 (number)
(last (sort (remove-if-not #'is-prime (factors number) :from-end t) #'<)))
The problem is that you are creating a list in potential-factors of all the numbers between 1 and n/2. That list takes a huge amount of memory and causes the program to crash. The good news is that you don't need to accumulate these numbers in a list, but simply use one number at a time. In factors replace the line (loop for x in (potential-factors number) with (loop for x from 1 to (ceiling (/ number 2))
That should do the trick.
I'm no mathematician, but another thought: The insight about dividing n by 2 seems to be that factors come in pairs. A is a factor of N only if A times B is N, so B has to be at least 2. But that logic can be extended, right? What about dividing by 3? Once you've checked to see if 3 is a factor, then there is no point in checking all numbers greater than 1/3 N. The same for 4, etc. The observation would seem to be that you really only need to check the numbers such that A is less than or equal to B -- so then what would the limit of that be? Well, if A = B, then A times B = A times A, which means that that in that case, A is the square root of N. So I would think you only need to check up as high as the square root N, instead of all the way up to N / 2.
But I'm no mathematician.
What do you think the result of (potential-factors 600851475143) is? How long would it take to compute a result and how much memory would the result need?
I have a simple search function for a property
that I am interested in, and a proof that the function is correct. I want to evaluate the function, and use the correctness proof to get the theorem for the original property. Unfortunately, evaluation in coq is very slow. As a trivial example, consider looking for square roots:
(*
Coq 8.4
A simple example to demonstrate searching.
Timings are rough and approximate.
*)
Require Import Peano_dec.
Definition SearchSqrtLoop :=
fix f i n := if eq_nat_dec (i * i) n
then i
else match i with
| 0 => 0 (* ~ Square n \/ n = 0 *)
| S j => f j n
end
.
Definition SearchSqrt n := SearchSqrtLoop n n.
(*
Compute SearchSqrt 484.
takes about 30 seconds.
*)
Theorem sqrt_484a : SearchSqrt 484 = 22.
apply eq_refl. (* 100 seconds *)
Qed. (* 50 seconds *)
Theorem sqrt_484b : SearchSqrt 484 = 22.
vm_compute. (* 30 seconds *)
apply eq_refl.
Qed. (* 30 seconds *)
Theorem sqrt_484c (a : nat) : SearchSqrt 484 = 22.
apply eq_refl. (* 100 seconds *)
Qed. (* 50 seconds *)
Theorem sqrt_484d (a : nat) : SearchSqrt 484 = 22.
vm_compute. (* 60 seconds *)
apply eq_refl.
Qed. (* 60 seconds *)
Now try the corresponding function in Python:
def SearchSqrt(n):
for i in range(n, -1, -1):
if i * i == n:
return i
return 0
or slightly more literally
def SearchSqrtLoop(i, n):
if i * i == n:
return i
if i == 0:
return 0
return SearchSqrtLoop(i - 1, n)
def SearchSqrt(n):
return SearchSqrtLoop(n, n)
The function is nearly instant in Python, but takes minutes in coq, depending on exactly how you try to call it. Also curious is that putting an extra variable in makes vm_compute take twice as long.
I understand that everything is done symbolically in coq, and thus slow, but it would be very useful if I could directly evaluate simple functions. Is there a way to do it? Just using native integers instead of linked lists would probably help a lot.
You'll get a speedup if you use binary arithmetic instead of unary arithmetic. Take a look at NArith and ZArith.
http://coq.inria.fr/library/
You'll also get a speedup if you run your code on OCaml, Haskell, or Scheme instead.
http://coq.inria.fr/refman/Reference-Manual025.html
There is a much more efficient function for finding square roots in the standard library (sqrt):
The following square root function is linear (and tail-recursive). With Peano representation, we can't do better. For faster algorithm, see Psqrt/Zsqrt/Nsqrt...
Require Import Coq.Init.Nat.
Theorem sqrt_484a_v2 : sqrt 484 = 22.
Time apply eq_refl.
Time Qed.
As Time tells us it works much faster (around 200 times faster than sqrt_484a).
The reason for this performance difference lies in the fact that SearchSqrt squares its first argument on each iteration, which is an expensive operation.
sqrt's implementation, on the other hand, is based on the Odd Number Theorem (1 + 3 + 5 + ... is a square number). One just needs to count the number of increasing intervals that can be fitted into the input argument n and that would be the integer square root of n. E.g. 22 = (1 + 3 + 5 + 7) + 6, which means there are 4 intervals (of lengths 1, 3, 5, and 7) in 22, so sqrt 22 = 4 (and we are not interested in the residual value 6).