Really bad numerical performance on finite difference derivative - math

I have this snippet:
pub trait LinAlg:
Mul<f32>
+ Add<Output = Self>
+ Sub<Output = Self>
+ Div<f32, Output = Self>
+ Copy
+ Sized
{
}
impl<T> LinAlg for T where
T: Mul<f32>
+ Add<Output = Self>
+ Sub<Output = Self>
+ Div<f32, Output = Self>
+ Copy
+ Sized
{
}
pub fn numerical_derivative<T>(x: f32, f: &dyn Fn(f32) -> T) -> T
where
T: LinAlg + Debug,
f32: Mul<T, Output = T>,
{
let h = 1e-3 as f32;
// Convoluted but rustc fails to understand h * h.
let denom = h + h;
let num = f(x + h) - f(x - h);
// Convoluted but rustc fails to understand num / denom.
<T as Div<f32>>::div(num, denom)
}
Which tries to provide a generic way to compute a numerical derivative.
I am testing it like this:
let epsilon = 1e-4;
let f = |x: f32| x * x;
let val = numerical_derivative(0.0, &f);
assert!(f32::abs(val - 0.0) < epsilon, "{}", val);
let val = numerical_derivative(1.0, &f);
assert!(f32::abs(val - 2.0) < epsilon, "{}", val);
let val = numerical_derivative(-1.0, &f);
assert!(f32::abs(val + 2.0) < epsilon, "{}", val);
let fp = |x: f32| numerical_derivative(x, &f);
let val = numerical_derivative(0.0, &fp);
assert!(f32::abs(val - 2.0) < epsilon, "{}", val);
let val = numerical_derivative(1.0, &fp);
assert!(f32::abs(val - 2.0) < epsilon, "{}", val);
let val = numerical_derivative(-1.0, &fp);
assert!(f32::abs(val - 2.0) < epsilon, "{}", val);
Something I am finding that I am curious about is, it seems this scheme (central difference) is very bad when you try to use it for high order derivatives like I am doing.
E.g. I get an error of 0.71321 for one of the second order derivative tests.
I know there is a finite difference scheme for second order derivatives, but is there a first order scheme that generalizes well into high order ones when used the way I am?

Related

Optimize parameters of a function (e.g., capacitor-charging) curve to fit data

In my attempt to fit a function of the form y = a * (1 - exp(-x / b)) to some given data, I'm a bit lost. I suspect the optimization package of apache-common-math might be of help, but I've not yet managed to use it successfully. Below you can find some code explaining what I'd like to achieve.
import kotlin.math.exp
import kotlin.random.Random
// Could be interpreted as a capacitor-charging curve with Vs = a and t = b
fun fGeneric(a: Double, b: Double, x: Double) = a * (1 - exp(-x / b))
fun fGiven(x: Double) = fGeneric(a = 10.0, b = 200.0, x = x)
fun fGivenWithNoise(x: Double) = fGiven(x) + Random.nextDouble(-0.1, 0.1)
fun main() {
val xs = (0..1000).map(Int::toDouble).toDoubleArray()
val ys = xs.map { x -> fGivenWithNoise(x) }.toDoubleArray()
// todo: From data, find a and b, such that fGeneric fits optimally.
}
Do I need to provide an implementation of the MultivariateDifferentiableVectorFunction interface? And if so, how would it need to look like?
Found a solution by using lbfgs4j instead:
package com.jaumo.ml.lifetimevalue
import com.github.lbfgs4j.LbfgsMinimizer
import com.github.lbfgs4j.liblbfgs.Function
import kotlin.math.exp
import kotlin.random.Random
// Could be interpreted as a capacitor-charging curve with Vs = a and t = b
fun fGeneric(a: Double, b: Double, x: Double) = a * (1 - exp(-x / b))
fun fGiven(x: Double) = fGeneric(a = 10.0, b = 200.0, x = x)
fun fGivenWithNoise(x: Double) = fGiven(x) + Random.nextDouble(-0.1, 0.1)
private fun subtractVectors(a: DoubleArray, b: DoubleArray): DoubleArray {
assert(a.size == b.size)
val result = DoubleArray(a.size)
(a.indices).forEach { dim ->
result[dim] = a[dim] - b[dim]
}
return result
}
fun main() {
val xs = (0..1000).map(Int::toDouble).toDoubleArray()
val ys = xs.map { x -> fGivenWithNoise(x) }.toDoubleArray()
val f = object : Function {
override fun getDimension(): Int {
return 2
}
override fun valueAt(x: DoubleArray): Double {
val maxVal = x[0]
val slowness = x[1]
val capacitorFunc = { x0: Double ->
maxVal * (1 - exp(-x0 / slowness))
}
return subtractVectors(xs.map(capacitorFunc).toDoubleArray(), ys)
.map { it * it }
.sum()
}
override fun gradientAt(x: DoubleArray): DoubleArray {
val a = valueAt(doubleArrayOf(x[0] - 0.001, x[1]))
val b = valueAt(doubleArrayOf(x[0] + 0.001, x[1]))
val c = valueAt(doubleArrayOf(x[0], x[1] - 0.001))
val d = valueAt(doubleArrayOf(x[0], x[1] + 0.001))
return doubleArrayOf(b - a, d - c)
}
}
val minimizer = LbfgsMinimizer()
val x = minimizer.minimize(f, doubleArrayOf(1.0, 10.0))
println(x[0])
println(x[1])
}
The result looks good:
9.998170586347115
200.14238710377768

Sun's position in Swift

I am trying to implement this solution for calculating the sun's position in Swift3. I then wrap this in another function that simply cycles through a day from midnight stepping every 10 minutes until 23:50.
I do not really understand R and there are some details of the answer I do not fully comprehend, notably what appears to be some sort of if/clamp function with the square brackets. I did my best, comparing with the Python version when I got confused. Otherwise the only differences are due to the use of NSDate, which simplified some of the code at the top.
Some of the values I get back seem correct and I can see the basis of a curve when I plot the results. However, the result from one call, say 7AM, and then the next, 7:10, are wildly different.
I strongly suspect I did something wrong with the clamping, and that minor changes in the inputs get mod/trunced in different ways and swing the output. But I can't spot it. Can anyone who understands this algo help?
Here's a sample of the output I'm getting:
2017-06-21 00:10:00 +0000 -16.0713262209521 31.7135341633943
2017-06-21 00:20:00 +0000 61.9971433936385 129.193513530349
2017-06-21 00:30:00 +0000 22.5263575559266 78.5445189561018
2017-06-21 00:40:00 +0000 29.5973897349096 275.081637736092
2017-06-21 00:50:00 +0000 41.9552795956374 262.989819486864
As you can see, it swings wildly between iterations. The Earth does not turn that way! My code follows, this version simply sends the results to the log:
class func julianDayFromDate(_ date: Date) -> Double {
let ti = date.timeIntervalSince1970
return ((ti / 86400.0) + 2440587)
}
class func sunPath(lat: Double, lon: Double, size: CGSize) -> UIImage {
var utzCal = Calendar(identifier: .gregorian)
utzCal.timeZone = TimeZone(secondsFromGMT: 0)!
let year = utzCal.component(.year, from: Date())
let june = DateComponents(calendar: utzCal, year: year, month: 6, day: 21).date!
// now we loop for every 10 minutes (2 degrees) and plot those points
for time in stride(from:0, to:(24 * 60), by: 10) {
let calcdate = june.addingTimeInterval(Double(time) * 60.0)
let (alt, az) = sun(date: calcdate, lat: lat, lon: lon)
print(calcdate, alt, az)
}
class func sun(date: Date, lat: Double, lon: Double) -> (altitude: Double, azimuth: Double) {
// these come in handy
let twopi = Double.pi * 2
let deg2rad = Double.pi / 180.0
// latitude to radians
let lat_radians = lat * deg2rad
// the Astronomer's Almanac method used here is based on Epoch 2000, so we need to
// convert the date into that format. We start by calculating "n", the number of
// days since 1 January 2000
let n = julianDayFromDate(date) - 2451545.0
// it continues by calculating the position in ecliptic coordinates,
// starting with the mean longitude of the sun in degrees, corrected for aberation
var meanlong_degrees = 280.460 + (0.9856474 * n)
meanlong_degrees = meanlong_degrees.truncatingRemainder(dividingBy: 360.0)
// and the mean anomaly in degrees
var meananomaly_degrees = 357.528 + (0.9856003 * n)
meananomaly_degrees = meananomaly_degrees.truncatingRemainder(dividingBy: 360.0)
let meananomaly_radians = meananomaly_degrees * deg2rad
// and finally, the eliptic longitude in degrees
var elipticlong_degrees = meanlong_degrees + (1.915 * sin(meananomaly_radians)) + (0.020 * sin(2 * meananomaly_radians))
elipticlong_degrees = elipticlong_degrees.truncatingRemainder(dividingBy: 360.0)
let elipticlong_radians = elipticlong_degrees * deg2rad
// now we want to convert that to equatorial coordinates
let obliquity_degrees = 23.439 - (0.0000004 * n)
let obliquity_radians = obliquity_degrees * deg2rad
// right ascention in radians
let num = cos(obliquity_radians) * sin(elipticlong_radians)
let den = cos(elipticlong_radians)
var ra_radians = atan(num / den)
ra_radians = ra_radians.truncatingRemainder(dividingBy: Double.pi)
if den < 0 {
ra_radians = ra_radians + Double.pi
} else if num < 0 {
ra_radians = ra_radians + twopi
}
// declination is simpler...
let dec_radians = asin(sin(obliquity_radians) * sin(elipticlong_radians))
// and from there, to local coordinates
// start with the UTZ sidereal time
let cal = Calendar.current
let h = Double(cal.component(.hour, from: date))
let m = Double(cal.component(.minute, from: date))
let f: Double
if h == 0 && m == 0 {
f = 0.0
} else if h == 0 {
f = 60.0 / m
} else if h == 0 {
f = 24.0 / h
} else {
f = (24.0 / h) + (60.0 / m)
}
var utz_sidereal_time = 6.697375 + 0.0657098242 * n + f
utz_sidereal_time = utz_sidereal_time.truncatingRemainder(dividingBy: 24.0)
// then convert that to local sidereal time
var localtime = utz_sidereal_time + lon / 15.0
localtime = localtime.truncatingRemainder(dividingBy: 24.0)
var localtime_radians = localtime * 15.0 * deg2rad
localtime_radians = localtime.truncatingRemainder(dividingBy: Double.pi)
// hour angle in radians
var hourangle_radians = localtime_radians - ra_radians
hourangle_radians = hourangle_radians.truncatingRemainder(dividingBy: twopi)
// get elevation in degrees
let elevation_radians = (asin(sin(dec_radians) * sin(lat_radians) + cos(dec_radians) * cos(lat_radians) * cos(hourangle_radians)))
let elevation_degrees = elevation_radians / deg2rad
// and azimuth
let azimuth_radians = asin( -cos(dec_radians) * sin(hourangle_radians) / cos(elevation_radians))
// now clamp the output
let azimuth_degrees: Double
if (sin(dec_radians) - sin(elevation_radians) * sin(lat_radians) < 0) {
azimuth_degrees = (Double.pi - azimuth_radians) / deg2rad
} else if (sin(azimuth_radians) < 0) {
azimuth_degrees = (azimuth_radians + twopi) / deg2rad
} else {
azimuth_degrees = azimuth_radians / deg2rad
}
return (elevation_degrees, azimuth_degrees)
}
Ok, after downloading an R interpreter for OSX, finding that it had no debugger, discovering that there are multiple ways to do a print all with their own caveats, etc etc, I found the problem I was looking for. It was indeed clamping one of the values incorrectly. Here is a working Swift3 version that should be easy to convert to any C-like language and easier to read than the originals. You will have to provide your own versions of the first two functions that work with the date format of your target platform. And the truncatingRemainer is someone's ferbile idea that there shouldn't be a % operator on Double, it's a normal MOD.
// convinience method to return a unit-epoch data from a julian date
class func dateFromJulianDay(_ julianDay: Double) -> Date {
let unixTime = (julianDay - 2440587) * 86400.0
return Date(timeIntervalSince1970: unixTime)
}
class func julianDayFromDate(_ date: Date) -> Double {
//==let JD = Integer(365.25 * (Y + 4716)) + Integer(30.6001 * (M +1)) +
let ti = date.timeIntervalSince1970
return ((ti / 86400.0) + 2440587.5)
}
// calculate the elevation and azimuth of the sun for a given date and location
class func sun(date: Date, lat: Double, lon: Double) -> (altitude: Double, azimuth: Double) {
// these come in handy
let twopi = Double.pi * 2
let deg2rad = Double.pi / 180.0
// latitude to radians
let lat_radians = lat * deg2rad
// the Astronomer's Almanac method used here is based on Epoch 2000, so we need to
// convert the date into that format. We start by calculating "n", the number of
// days since 1 January 2000. So if your date format is 1970-based, convert that
// a pure julian date and pass that in. If your date is 2000-based, then
// just let n = date
let n = julianDayFromDate(date) - 2451545.0
// it continues by calculating the position in ecliptic coordinates,
// starting with the mean longitude of the sun in degrees, corrected for aberation
var meanlong_degrees = 280.460 + (0.9856474 * n)
meanlong_degrees = meanlong_degrees.truncatingRemainder(dividingBy: 360.0)
// and the mean anomaly in degrees
var meananomaly_degrees = 357.528 + (0.9856003 * n)
meananomaly_degrees = meananomaly_degrees.truncatingRemainder(dividingBy: 360.0)
let meananomaly_radians = meananomaly_degrees * deg2rad
// and finally, the eliptic longitude in degrees
var elipticlong_degrees = meanlong_degrees + (1.915 * sin(meananomaly_radians)) + (0.020 * sin(2 * meananomaly_radians))
elipticlong_degrees = elipticlong_degrees.truncatingRemainder(dividingBy: 360.0)
let elipticlong_radians = elipticlong_degrees * deg2rad
// now we want to convert that to equatorial coordinates
let obliquity_degrees = 23.439 - (0.0000004 * n)
let obliquity_radians = obliquity_degrees * deg2rad
// right ascention in radians
let num = cos(obliquity_radians) * sin(elipticlong_radians)
let den = cos(elipticlong_radians)
var ra_radians = atan(num / den)
ra_radians = ra_radians.truncatingRemainder(dividingBy: Double.pi)
if den < 0 {
ra_radians = ra_radians + Double.pi
} else if num < 0 {
ra_radians = ra_radians + twopi
}
// declination is simpler...
let dec_radians = asin(sin(obliquity_radians) * sin(elipticlong_radians))
// and from there, to local coordinates
// start with the UTZ sidereal time, which is probably a lot easier in non-Swift languages
var utzCal = Calendar(identifier: .gregorian)
utzCal.timeZone = TimeZone(secondsFromGMT: 0)!
let h = Double(utzCal.component(.hour, from: date))
let m = Double(utzCal.component(.minute, from: date))
let f: Double // universal time in hours and decimals (not days!)
if h == 0 && m == 0 {
f = 0.0
} else if h == 0 {
f = m / 60.0
} else if m == 0 {
f = h
} else {
f = h + (m / 60.0)
}
var utz_sidereal_time = 6.697375 + 0.0657098242 * n + f
utz_sidereal_time = utz_sidereal_time.truncatingRemainder(dividingBy: 24.0)
// then convert that to local sidereal time
var localtime = utz_sidereal_time + lon / 15.0
localtime = localtime.truncatingRemainder(dividingBy: 24.0)
let localtime_radians = localtime * 15.0 * deg2rad
// hour angle in radians
var hourangle_radians = localtime_radians - ra_radians
hourangle_radians = hourangle_radians.truncatingRemainder(dividingBy: twopi)
// get elevation in degrees
let elevation_radians = (asin(sin(dec_radians) * sin(lat_radians) + cos(dec_radians) * cos(lat_radians) * cos(hourangle_radians)))
let elevation_degrees = elevation_radians / deg2rad
// and azimuth
let azimuth_radians = asin( -cos(dec_radians) * sin(hourangle_radians) / cos(elevation_radians))
// now clamp the output
let azimuth_degrees: Double
if (sin(dec_radians) - sin(elevation_radians) * sin(lat_radians) < 0) {
azimuth_degrees = (Double.pi - azimuth_radians) / deg2rad
} else if (sin(azimuth_radians) < 0) {
azimuth_degrees = (azimuth_radians + twopi) / deg2rad
} else {
azimuth_degrees = azimuth_radians / deg2rad
}
// all done!
return (elevation_degrees, azimuth_degrees)
}

F# adding polynomials recursively

I'm trying to write a function in F# that adds polynomials recursively. My polynomials can be represented as a list of tuples.
For example, 2x^4 + 3x^2 + x + 5 is equal to [(2.0,4);(3.0,2);(1.0,1);(5.0,0)]
All polynomials are properly structured (no repeated terms with the same degree, no terms with zero coefficients unless it is the zero polynomial, terms sorted by decreasing exponent no empty input list).
I'm having trouble doing this. Here is my code
type term = float * int
type poly = term list
let rec atp(t:term,p:poly):poly =
match p with
| [] -> []
| (a, b) :: tail -> if snd t = b then (fst t + a, b) :: [] elif snd t > b then t :: [] else ([]) :: atp(t, tail)
(* val atp : t:term * p:poly -> poly *)
let rec addpolys(p1:poly,p2:poly):poly =
match p1 with
| [] -> []
| (a,b) :: tail -> atp((a,b), p2) # addpolys(tail, p2)
I have two polynomials
val p2 : poly = [(4.5, 7); (3.0, 4); (10.5, 3); (2.25, 2)]
val p1 : poly = [(3.0, 5); (2.0, 2); (7.0, 1); (1.5, 0)]
and when I call the function, my result is
val p4 : poly =
[(4.5, 7); (3.0, 5); (3.0, 4); (3.0, 5); (10.5, 3); (3.0, 5); (4.25, 2)]
When the correct answer is
[(4.5, 7); (3.0, 5); (3.0, 4); (10.5, 3); (4.25, 2); (7.0, 1); (1.5, 0)]
Unfortunately your code does not compile therefore it is difficult for me to understand your intentions. But I've got an own implementation for your problem. Maybe it will help you:
// addpoly: (float * 'a) list -> (float * 'a) list -> (float * 'a) list
let rec addpoly p1 p2 =
match (p1, p2) with
| [], p2 -> p2
| p1, [] -> p1
| (a1, n1)::p1s, (a2, n2)::p2s ->
if n1 < n2 then (a2, n2) :: addpoly p1 p2s
elif n1 > n2 then (a1, n1) :: addpoly p1s p2
else (a1+a2, n1) :: addpoly p1s p2s
let p1 = [(3.0, 5); (2.0, 2); ( 7.0, 1); (1.5, 0)]
let p2 = [(4.5, 7); (3.0, 4); (10.5, 3); (2.25, 2)]
let q = addpoly p1 p2
// val q : (float * int) list =
// [(4.5, 7); (3.0, 5); (3.0, 4); (10.5, 3); (4.25, 2); (7.0, 1); (1.5, 0)]
I would like to make a little note. When you change the representation of the
polynomials a little bit then you can simplify the implementation of your function. You can express a polynomial as a list of its coefficients.
For example when you have this polynomial
p1 = 5.0x^5 + 2.0x^2 + 7.0x
you can write it also like this
p1 = 1.5x^0 + 7.0x^1 + 2.0x^2 + 0.0x^3 + 0.0x^4 + 5.0x^5
Therefore you are able to define the polynomial with this list:
let p1 = [1.5; 7.0; 2.0; 0.0; 0.0; 5.0]
Here are two functions which operates on the representation. polyval calculates the result for a given value and polyadd adds two polynomials. There implementation are rather simple:
// p1 = 1.5x^0 + 7.0x^1 + 2.0x^2 + 0.0x^3 + 0.0x^4 + 5.0x^5
let p1 = [1.5; 7.0; 2.0; 0.0; 0.0; 5.0]
// p2 = 0.0x^0 + 0.0x^1 + 2.25x^2 + 10.5x^3 + 3.0x^4 + 0.0x^5 + 0.0x^6 + 4.5x^7
let p2 = [0.0; 0.0; 2.25; 10.5; 3.0; 0.0; 0.0; 4.5]
// polyval: float list -> float -> float
let rec polyval ps x =
match ps with
| [] -> 0.0
| p::ps -> p + x * (polyval ps x)
// polyadd: float int -> float int -> float int
let rec polyadd ps qs =
match (ps, qs) with
| [], ys -> ys
| xs, [] -> xs
| x::xs, y::ys -> (x+y)::polyadd xs ys
let v = polyval p1 2.3
// val v : float = 349.99715
let p = polyadd p1 p2
// val p : float list = [1.5; 7.0; 4.25; 10.5; 3.0; 5.0; 0.0; 4.5]
Here's a completely generic, tail-recursive implementation:
let inline addPolys xs ys =
let rec imp acc = function
| (coeffx, degx)::xt, (coeffy, degy)::yt when degx = degy ->
imp ((coeffx + coeffy, degx)::acc) (xt, yt)
| (coeffx, degx)::xt, (coeffy, degy)::yt when degx > degy ->
imp ((coeffx, degx)::acc) (xt, (coeffy, degy)::yt)
| xs, yh::yt -> imp (yh::acc) (xs, yt)
| xh::xt, [] -> imp (xh::acc) (xt, [])
| [], yh::yt -> imp (yh::acc) ([], yt)
| [], [] -> acc
imp [] (xs, ys) |> List.rev
It has the type:
xs:( ^a * 'b) list -> ys:( ^a * 'b) list -> ( ^a * 'b) list
when ^a : (static member ( + ) : ^a * ^a -> ^a) and 'b : comparison
Since float has the member +, and int supports comparison, the type float * int matches these generic constraints:
> addPolys p1 p2;;
val it : (float * int) list =
[(4.5, 7); (3.0, 5); (3.0, 4); (10.5, 3); (4.25, 2); (7.0, 1); (1.5, 0)]

F# closures on mailbox processor threading failure

So I am doing a some batch computation very cpu intensive on books. And I built a tracker to track the computation of tasks. I close on a mailboxprocesser which all runs fine without parallelizaton but when I put a array.parallel.map or and async workflow the mailboxprocesser fails. I want to know why?
type timerMessage =
| Start of int
| Tick of bool
let timer = MailboxProcessor.Start(fun mbox ->
let inputloop() = async {
let progress = ref 0
let amount = ref 0
let start = ref System.DateTime.UtcNow
while true do
let! msg = mbox.Receive()
match msg with
| Start(i) -> amount := i
progress := 0
start := System.DateTime.UtcNow
| Tick(b) -> if !amount = 0 then ()
else
progress := !progress + 1
let el = System.DateTime.UtcNow - !start
let eta = int ((el.TotalSeconds/float !progress)*(float (!amount - !progress)))
let etas = (int (eta / 3600)).ToString() + ":" + (int ((eta % 3600) / 60)).ToString() + ":" + (eta % 60).ToString()
System.Console.Clear()
System.Console.Write((!progress).ToString() + "/" + (!amount).ToString() + " Completed [] Estimated Time Remaining:" + etas)
} inputloop() )
let computeBook (author :string) path =
let rs = ReadToStrings(path)
let bk = StringsToBook rs
let mt = createMatrix bk 100 10 //size 100 //span 10
let res = GetResults mt
//do stuff
timer.Post(Tick(true))
(author,path,res)
let partAopA = //clip head clip foot no word mods
let lss = seq {for x in processtree do
for y in (snd x) do
yield ((fst x),y) }
let ls = Seq.toArray lss //task list
timer.Post(Start(ls.Length)) //start counter
let compls = Array.map (fun l -> computeBook (fst l) (snd l) ) ls //Array.Parallel.map fails here the same as below async if I put async blcoks around the computbook call
//let res = compls |> Async.Parallel |> Async.RunSynchronously
writeResults compls outputfolder |> ignore
compls

Optimization of Fibonacci sequence generating algorithm

As we all know, the simplest algorithm to generate Fibonacci sequence is as follows:
if(n<=0) return 0;
else if(n==1) return 1;
f(n) = f(n-1) + f(n-2);
But this algorithm has some repetitive calculation. For example, if you calculate f(5), it will calculate f(4) and f(3). When you calculate f(4), it will again calculate both f(3) and f(2). Could someone give me a more time-efficient recursive algorithm?
I have read about some of the methods for calculating Fibonacci with efficient time complexity following are some of them -
Method 1 - Dynamic Programming
Now here the substructure is commonly known hence I'll straightly Jump to the solution -
static int fib(int n)
{
int f[] = new int[n+2]; // 1 extra to handle case, n = 0
int i;
f[0] = 0;
f[1] = 1;
for (i = 2; i <= n; i++)
{
f[i] = f[i-1] + f[i-2];
}
return f[n];
}
A space-optimized version of above can be done as follows -
static int fib(int n)
{
int a = 0, b = 1, c;
if (n == 0)
return a;
for (int i = 2; i <= n; i++)
{
c = a + b;
a = b;
b = c;
}
return b;
}
Method 2- ( Using power of the matrix {{1,1},{1,0}} )
This an O(n) which relies on the fact that if we n times multiply the matrix M = {{1,1},{1,0}} to itself (in other words calculate power(M, n )), then we get the (n+1)th Fibonacci number as the element at row and column (0, 0) in the resultant matrix. This solution would have O(n) time.
The matrix representation gives the following closed expression for the Fibonacci numbers:
fibonaccimatrix
static int fib(int n)
{
int F[][] = new int[][]{{1,1},{1,0}};
if (n == 0)
return 0;
power(F, n-1);
return F[0][0];
}
/*multiplies 2 matrices F and M of size 2*2, and
puts the multiplication result back to F[][] */
static void multiply(int F[][], int M[][])
{
int x = F[0][0]*M[0][0] + F[0][1]*M[1][0];
int y = F[0][0]*M[0][1] + F[0][1]*M[1][1];
int z = F[1][0]*M[0][0] + F[1][1]*M[1][0];
int w = F[1][0]*M[0][1] + F[1][1]*M[1][1];
F[0][0] = x;
F[0][1] = y;
F[1][0] = z;
F[1][1] = w;
}
/*function that calculates F[][] raise to the power n and puts the
result in F[][]*/
static void power(int F[][], int n)
{
int i;
int M[][] = new int[][]{{1,1},{1,0}};
// n - 1 times multiply the matrix to {{1,0},{0,1}}
for (i = 2; i <= n; i++)
multiply(F, M);
}
This can be optimized to work in O(Logn) time complexity. We can do recursive multiplication to get power(M, n) in the previous method.
static int fib(int n)
{
int F[][] = new int[][]{{1,1},{1,0}};
if (n == 0)
return 0;
power(F, n-1);
return F[0][0];
}
static void multiply(int F[][], int M[][])
{
int x = F[0][0]*M[0][0] + F[0][1]*M[1][0];
int y = F[0][0]*M[0][1] + F[0][1]*M[1][1];
int z = F[1][0]*M[0][0] + F[1][1]*M[1][0];
int w = F[1][0]*M[0][1] + F[1][1]*M[1][1];
F[0][0] = x;
F[0][1] = y;
F[1][0] = z;
F[1][1] = w;
}
static void power(int F[][], int n)
{
if( n == 0 || n == 1)
return;
int M[][] = new int[][]{{1,1},{1,0}};
power(F, n/2);
multiply(F, F);
if (n%2 != 0)
multiply(F, M);
}
Method 3 (O(log n) Time)
Below is one more interesting recurrence formula that can be used to find nth Fibonacci Number in O(log n) time.
If n is even then k = n/2:
F(n) = [2*F(k-1) + F(k)]*F(k)
If n is odd then k = (n + 1)/2
F(n) = F(k)*F(k) + F(k-1)*F(k-1)
How does this formula work?
The formula can be derived from the above matrix equation.
fibonaccimatrix
Taking determinant on both sides, we get
(-1)n = Fn+1Fn-1 – Fn2
Moreover, since AnAm = An+m for any square matrix A, the following identities can be derived (they are obtained from two different coefficients of the matrix product)
FmFn + Fm-1Fn-1 = Fm+n-1
By putting n = n+1,
FmFn+1 + Fm-1Fn = Fm+n
Putting m = n
F2n-1 = Fn2 + Fn-12
F2n = (Fn-1 + Fn+1)Fn = (2Fn-1 + Fn)Fn (Source: Wiki)
To get the formula to be proved, we simply need to do the following
If n is even, we can put k = n/2
If n is odd, we can put k = (n+1)/2
public static int fib(int n)
{
if (n == 0)
return 0;
if (n == 1 || n == 2)
return (f[n] = 1);
// If fib(n) is already computed
if (f[n] != 0)
return f[n];
int k = (n & 1) == 1? (n + 1) / 2
: n / 2;
// Applyting above formula [See value
// n&1 is 1 if n is odd, else 0.
f[n] = (n & 1) == 1? (fib(k) * fib(k) +
fib(k - 1) * fib(k - 1))
: (2 * fib(k - 1) + fib(k))
* fib(k);
return f[n];
}
Method 4 - Using a formula
In this method, we directly implement the formula for the nth term in the Fibonacci series. Time O(1) Space O(1)
Fn = {[(√5 + 1)/2] ^ n} / √5
static int fib(int n) {
double phi = (1 + Math.sqrt(5)) / 2;
return (int) Math.round(Math.pow(phi, n)
/ Math.sqrt(5));
}
Reference: http://www.maths.surrey.ac.uk/hosted-sites/R.Knott/Fibonacci/fibFormula.html
Look here for implementation in Erlang which uses formula
. It shows nice linear resulting behavior because in O(M(n) log n) part M(n) is exponential for big numbers. It calculates fib of one million in 2s where result has 208988 digits. The trick is that you can compute exponentiation in O(log n) multiplications using (tail) recursive formula (tail means with O(1) space when used proper compiler or rewrite to cycle):
% compute X^N
power(X, N) when is_integer(N), N >= 0 ->
power(N, X, 1).
power(0, _, Acc) ->
Acc;
power(N, X, Acc) ->
if N rem 2 =:= 1 ->
power(N - 1, X, Acc * X);
true ->
power(N div 2, X * X, Acc)
end.
where X and Acc you substitute with matrices. X will be initiated with and Acc with identity I equals to .
One simple way is to calculate it iteratively instead of recursively. This will calculate F(n) in linear time.
def fib(n):
a,b = 0,1
for i in range(n):
a,b = a+b,a
return a
Hint: One way you achieve faster results is by using Binet's formula:
Here is a way of doing it in Python:
from decimal import *
def fib(n):
return int((Decimal(1.6180339)**Decimal(n)-Decimal(-0.6180339)**Decimal(n))/Decimal(2.236067977))
you can save your results and use them :
public static long[] fibs;
public long fib(int n) {
fibs = new long[n];
return internalFib(n);
}
public long internalFib(int n) {
if (n<=2) return 1;
fibs[n-1] = fibs[n-1]==0 ? internalFib(n-1) : fibs[n-1];
fibs[n-2] = fibs[n-2]==0 ? internalFib(n-2) : fibs[n-2];
return fibs[n-1]+fibs[n-2];
}
F(n) = (φ^n)/√5 and round to nearest integer, where φ is the golden ratio....
φ^n can be calculated in O(lg(n)) time hence F(n) can be calculated in O(lg(n)) time.
// D Programming Language
void vFibonacci ( const ulong X, const ulong Y, const int Limit ) {
// Equivalent : if ( Limit != 10 ). Former ( Limit ^ 0xA ) is More Efficient However.
if ( Limit ^ 0xA ) {
write ( Y, " " ) ;
vFibonacci ( Y, Y + X, Limit + 1 ) ;
} ;
} ;
// Call As
// By Default the Limit is 10 Numbers
vFibonacci ( 0, 1, 0 ) ;
EDIT: I actually think Hynek Vychodil's answer is superior to mine, but I'm leaving this here just in case someone is looking for an alternate method.
I think the other methods are all valid, but not optimal. Using Binet's formula should give you the right answer in principle, but rounding to the closest integer will give some problems for large values of n. The other solutions will unnecessarily recalculate the values upto n every time you call the function, and so the function is not optimized for repeated calling.
In my opinion the best thing to do is to define a global array and then to add new values to the array IF needed. In Python:
import numpy
fibo=numpy.array([1,1])
last_index=fibo.size
def fib(n):
global fibo,last_index
if (n>0):
if(n>last_index):
for i in range(last_index+1,n+1):
fibo=numpy.concatenate((fibo,numpy.array([fibo[i-2]+fibo[i-3]])))
last_index=fibo.size
return fibo[n-1]
else:
print "fib called for index less than 1"
quit()
Naturally, if you need to call fib for n>80 (approximately) then you will need to implement arbitrary precision integers, which is easy to do in python.
This will execute faster, O(n)
def fibo(n):
a, b = 0, 1
for i in range(n):
if i == 0:
print(i)
elif i == 1:
print(i)
else:
temp = a
a = b
b += temp
print(b)
n = int(input())
fibo(n)

Resources