I want to start with very simple math fact - if we draw right triangle and two of edges of this triangle have length equal to sqrt(2). Area of this triangle is of course 1 (because: 1/2*a*h).
Another fact is that area under function sin(x) from 0 to pi/2 is also equal to 1.
Let's use those facts to exploit groovy closures to estimate pi and sqrt(2).
We should start with tests - this time we will use spock with "where:" block.
For pi this is also very simple test:
Definite integral is quite simple (from the numerical recipes point of view we can achieve much better results even with this naive approach but I want to keep this simple).
After this loop we should return x which is our result.
What else can we do better?
Every math lover will tell us other things but IT guys will focus on poor API and unnecessary method. Lets replace this simple solution with this:
Another fact is that area under function sin(x) from 0 to pi/2 is also equal to 1.
Let's use those facts to exploit groovy closures to estimate pi and sqrt(2).
Clone repo:
git clone https://github.com/piotrpietrzak/gatchaman.git
git checkout origin/groovypi
We should start with tests - this time we will use spock with "where:" block.
def "should converge to square root of two"(scale, sumToLimit, expectedResult) { expect: new DefiniteIntegral() .compute(scale, sumToLimit , { it }) == expectedResult where: scale | sumToLimit | expectedResult 1 | 1 | 1.4
2 | 1 | 1.41
3 | 1 | 1.414
4 | 1 | 1.4142
5 | 1 | 1.41421
6 | 1 | 1.414214
}
For pi this is also very simple test:
def "should converge to pi"(scale, sumToLimit, expectedResult) { expect: new DefiniteIntegral() .compute(scale, sumToLimit, { Math.sin(it) }) * 2 == expectedResult where: scale | sumToLimit | expectedResult 1 | 1 | 3.2
2 | 1 | 3.14
3 | 1 | 3.142
4 | 1 | 3.1416
5 | 1 | 3.14160
6 | 1 | 3.141592
}
Definite integral is quite simple (from the numerical recipes point of view we can achieve much better results even with this naive approach but I want to keep this simple).
while (sum < integrateTo) {
x += step
sum += function(x) * step
}
After this loop we should return x which is our result.
What else can we do better?
Every math lover will tell us other things but IT guys will focus on poor API and unnecessary method. Lets replace this simple solution with this:
class IntegrationClosure { final Closure<BigInteger> compute = { Integer scale, BigDecimal integrateTo, Closure<BigDecimal> function -> BigDecimal sum = 0; BigDecimal x = 0; BigDecimal step = BigDecimal.valueOf(1, scale) while (sum < integrateTo) { x += step sum += function(x) * step } x } }
No comments:
Post a Comment