Kotlin Calculating with BigDecimal vs Double - kotlin

I have 2 Functions. One uses BigInteger and BigDecimal. I want to calculate sin(z) using the Taylor series:
Here is my code:
fun sinus(z: BigDecimal, upperBound: Int = 100): BigDecimal = calcSin(z, upperBound)
fun cosinus(z: BigDecimal, upperBound: Int = 100): BigDecimal = calcSin(z, upperBound, false)
fun calcSin(z: BigDecimal, upperBound: Int = 100, isSin: Boolean = true): BigDecimal {
var erg: BigDecimal = BigDecimal.ZERO
for (n in 0..upperBound) {
// val zaehler = (-1.0).pow(n).toBigDecimal() * z.pow(2 * n + (if (isSin) 1 else 0))
// val nenner = fac(2 * n + (if (isSin) 1 else 0)).toBigDecimal()
val zaehler = (-1.0).pow(n).toBigDecimal() * z.pow(2 * n + 1)
val nenner = fac(2 * n + 1).toBigDecimal()
erg += (zaehler / nenner)
}
return erg
}
fun calcSin(z: Double, upperBound: Int = 100): Double {
var res = 0.0
for (n in 0..upperBound) {
val zaehler = (-1.0).pow(n) * z.pow(2 * n + 1)
val nenner = fac(2 * n + 1, true)
res += (zaehler / nenner)
}
return res
}
fun fac(n: Int): BigInteger = if (n == 0 || n == 1) BigInteger.ONE else n.toBigInteger() * fac(n - 1)
fun fac(n: Int, dummy: Boolean): Double = if (n == 0 || n == 1) 1.0 else n.toDouble() * fac(n - 1, dummy)
According to Google, Sin(1) is
0.8414709848
The Output of the following is however:
println("Sinus 1: ${sinus(1.0.toBigDecimal())}")
println("Sinus 1: ${sinus(1.0.toBigDecimal()).toDouble()}")
println("Sinus 1: ${sinus(1.0.toBigDecimal(), 1000)}")
println("Sinus 1: ${calcSin(1.0)}")
Output:
Sinus 1: 0.8414373208078281027995610599000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Sinus 1: 0.8414373208078281
Sinus 1: 0.8414373208078281027995610599000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Sinus 1: 0.8414709848078965
Wha am I missing? Why does the Double-Variant gives the correct value, while The BigDecimal doesn't? Even with 1000 Iterations.
The commented out code was meant for calculation Cos as well, but wanted to figure out that Problem first, so i made both Functions look the same

In the BigDecimal variant, try replacing erg += (zaehler / nenner) with erg += (zaehler.divide(nenner, 20, RoundingMode.HALF_EVEN))
I suspect that the defaults for scaling the division results (as described here https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/math/BigDecimal.html) are not what you want.
BTW - I assume that performance is not part of the exercise, otherwise your implementation of factorial is a low hanging fruit.

Related

Assignment problem - What am I doing wrong?

I am working on image seam carving project, looking for some help. Can someone tell me what am I doing wrong here, Hyperskill is not accepting my solution. I am pretty sure I did not understand the project statement correctly. (I’ve been fighting it for a week)
Project: https://hyperskill.org/projects/100/stages/553/implement
First I am finding the minimum seam from all possible seams.
var minX = 0
// (minSeamX, 0) would be the coordinate of the minimum seam
var minSeamX = 0
var minSeam = Double.MAX_VALUE
//Starting from top left find the sum of pixel energies for all possible seams(#width number of possible seams)
for (column in 0 until width) {
var totalSeam = 0.0
var xHigh = column
var xLow = column
var min = Double.MAX_VALUE
for (y in 0 until height) {
for (x in xLow..xHigh) {
if (x < 0 || x > width - 1) continue
val energy = calculateEnergy(x, y, bufferedImage)
// println("Energy $x $y $energy")
if (energy < min) {
min = energy
minX = x
}
}
totalSeam += min
min = Double.MAX_VALUE
xLow = minX - 1
xHigh = minX + 1
}
if (totalSeam < minSeam) {
minSeamX = column
minSeam = totalSeam
}
println("total:$totalSeam")
}
after that I am applying the color to the minimum seam pixels
var xLow = minSeamX
var xHigh = minSeamX
var min = Double.MAX_VALUE
for (y in 0 until height) {
for (x in xLow..xHigh) {
val energy = calculateEnergy(x, y, bufferedImage)
if (energy < min) {
min = energy
minX = x
}
}
val createGraphics = applyColor(outImage, minX, y)
min = Double.MAX_VALUE
xLow = minX - 1
xHigh = minX + 1
}
Complete code
package seamcarving
import java.awt.Color
import java.awt.Graphics2D
import java.awt.image.BufferedImage
import java.io.File
import javax.imageio.ImageIO
import kotlin.math.pow
import kotlin.math.sqrt
fun main(args: Array<String>) {
val bufferedImage = ImageIO.read(File("/Users/name/Downloads/images/blue.png"))
val outImage = ImageIO.read(File("/Users/name/Downloads/images/blue.png"))
val height = bufferedImage.height
val width = bufferedImage.width
var minX = 0
// (minSeamX, 0) would be the coordinate of the minimum seam
var minSeamX = 0
var minSeam = Double.MAX_VALUE
//Starting from top left find the sum of pixel energies for all possible seams(#width number of possible seams)
for (column in 0 until width) {
var totalSeam = 0.0
var xHigh = column
var xLow = column
var min = Double.MAX_VALUE
for (y in 0 until height) {
for (x in xLow..xHigh) {
if (x < 0 || x > width - 1) continue
val energy = calculateEnergy(x, y, bufferedImage)
// println("Energy $x $y $energy")
if (energy < min) {
min = energy
minX = x
}
}
totalSeam += min
min = Double.MAX_VALUE
xLow = minX - 1
xHigh = minX + 1
}
if (totalSeam < minSeam) {
minSeamX = column
minSeam = totalSeam
}
println("total:$totalSeam")
}
var xLow = minSeamX
var xHigh = minSeamX
var min = Double.MAX_VALUE
for (y in 0 until height) {
for (x in xLow..xHigh) {
val energy = calculateEnergy(x, y, bufferedImage)
if (energy < min) {
min = energy
minX = x
}
}
val createGraphics = applyColor(outImage, minX, y)
min = Double.MAX_VALUE
xLow = minX - 1
xHigh = minX + 1
}
// for (x in 0 until width) {
// for (y in 0 until height) {
// val intensity = ((255.0 * array[x][y]) / max).toInt()
// val color = Color(intensity, intensity, intensity)
//// outputImage.setRGB(x, y, intensity)
// createGraphics.paint = color
// createGraphics.fillRect(x, y, 1, 1)
// }
// }
ImageIO.write(outImage, "png", File("out.png"))
// ImageIO.write(bufferedImage, "png", File("${args[3]}"))
}
private fun applyColor(outputImage: BufferedImage, maxX: Int, maxY: Int): Graphics2D? {
val createGraphics = outputImage.createGraphics()
val color = Color(255, 0, 0)
createGraphics.paint = color
createGraphics.fillRect(maxX, maxY, 1, 1)
return createGraphics
}
private fun calculateEnergy(x: Int, y: Int, bufferedImage: BufferedImage): Double {
return sqrt(getXGradient(x, y, bufferedImage) + getYGradient(x, y, bufferedImage))
}
fun getXGradient(x: Int, y: Int, inImage: BufferedImage): Double {
val width = inImage.width
var xx = x
var yy = y
if (x == 0) xx = 1
if (x == width - 1) xx = x - 1
val lc = Color(inImage.getRGB(xx - 1, yy))
val rc = Color(inImage.getRGB(xx + 1, yy))
return (lc.red - rc.red).toDouble().pow(2.0) + (lc.green - rc.green).toDouble().pow(2.0) + (lc.blue - rc.blue).toDouble().pow(2.0)
}
fun getYGradient(x: Int, y: Int, inImage: BufferedImage): Double {
val height = inImage.height
var xx = x
var yy = y
if (y == 0) yy = 1
if (y == height - 1) yy = y - 1
val lc = Color(inImage.getRGB(xx, yy - 1))
val rc = Color(inImage.getRGB(xx, yy + 1))
return (lc.red - rc.red).toDouble().pow(2.0) + (lc.green - rc.green).toDouble().pow(2.0) + (lc.blue - rc.blue).toDouble().pow(2.0)
}

Bankers' rounding for BigQuery

Simple question what is the way to use bankers' rounding in BigQuery.
The only thing which I can find is:
BAD WAY to do it but still works:
CREATE TEMP FUNCTION test(num FLOAT64, decimalPlaces INT64)
RETURNS FLOAT64
LANGUAGE js AS """
var d = decimalPlaces || 0;
var m = Math.pow(10, d);
var n = +(d ? num * m : num).toFixed(8); // Avoid rounding errors
var i = Math.floor(n), f = n - i;
var e = 1e-8; // Allow for rounding errors in f
var r = (f > 0.5 - e && f < 0.5 + e) ?
((i % 2 == 0) ? i : i + 1) : Math.round(n);
return d ? r / m : r;
""";
SELECT ROUND(1.525,2)
There is a simpler way of calculating it:
CREATE TEMP FUNCTION bankersRound(num FLOAT64, decimals INT64)
RETURNS FLOAT64
LANGUAGE js AS """
var scale = Math.pow(10, decimals);
var result = value = (Math.round((num * scale) / 2) * 2) / scale;
return result;
""";
Bad way, but still works:
CREATE TEMP FUNCTION test(num FLOAT64, decimalPlaces INT64)
RETURNS FLOAT64
LANGUAGE js AS """
var d = decimalPlaces || 0;
var m = Math.pow(10, d);
var n = +(d ? num * m : num).toFixed(8); // Avoid rounding errors
var i = Math.floor(n), f = n - i;
var e = 1e-8; // Allow for rounding errors in f
var r = (f > 0.5 - e && f < 0.5 + e) ?
((i % 2 == 0) ? i : i + 1) : Math.round(n);
return d ? r / m : r;
""";
SELECT ROUND(1.525,2)

Using groupBy/groupingBy/aggregate to sum into smaller buckets in parallel?

I've got a collection of "stuff", and I'd like to sum it into smaller buckets. (In my particular case, I'm downsampling a luma channel of an image by 8x.)
I'd like it to be as fast as possible on your average multi-core android device, which I think means coroutine-per-bucket. (because there isn't any reason to play with IntAdders if I don't have to)
The naive linear solution:
val SCALE = 8
image.planes[0].buffer.toByteArray().forEachIndexed { index, byte ->
val x1 = index % image.width
val y1 = index / image.width
val x2 = x1 / SCALE
val y2 = y1 / SCALE
val quadIdx = y2 * (image.width / SCALE) + x2
summedQuadLum[quadIdx] += (byte.toInt() and 0xFF)
}
That isn't great - needs to pre-declare the summedQuadLum collection, and doesn't have any chance of parallel work.
I'd love to use groupBy, or groupingBy? or aggregate?) but those all seem to use the values to determine the new keys, and I need to use the key to determine the new keys. I think the least overhead is withIndex which could be done as
val thumbSums = bufferArray.withIndex().groupingBy { (idx, _) ->
val x1 = idx % previewImageDimension.width
val y1 = idx / previewImageDimension.width
val x2 = x1 / SCALE
val y2 = y1 / SCALE
y2 * (previewImageDimension.width / SCALE) + x2
}.aggregate { _, acc: Int?, (_, lum), _ ->
(acc ?: 0) + (lum.toInt() and 0xFF)
}.values.toIntArray()
Much better, it is really close - if I could figure out how to sum each bucket in a coroutine, I think it would be as good as can be expected.
So after groupingBy we have a Grouping object, which we can use to aggregate values. It's important to notice the grouping itself has not been done yet, we basically have a description how to group the values and an iterator of the original array. From here we have a few options:
Create a Channel from the iterator and launch a few worker coroutines to consume it in parallel. Channels support fan-out, so every item in the source is processed by one worker only. The problem here is all the workers need to update different items in the resulting array, so synchronization is required and that's where it gets tricky and likely inefficient.
To avoid multiple workers to write to the same item, we need to tell each of them what items to process. That mean either each of the worker should process all the items, picking only suitable or we should precalculate the groups in advance and feed the workers with the groups. Both approaches have pretty much the same performance as the serial algorithm, so do not make any sense.
So to parallelize it efficiently we want to avoid having a shared mutable state, because it requires synchronization. Obviously we don't want to precalculate the groups also.
My suggestion here is to come from another side - instead of mapping original array to sampled one, let's map sampled array to the original. So we say
This approaches makes each value to be calculated independently by one worker, so no synchronization needed. Now we can implement it like this:
suspend fun sample() {
val asyncFactor = 8
val src = Image(bufferArray, width)
val dst = Image(src.width / SCALE, src.height / SCALE)
val chunkSize = dst.sizeBytes / asyncFactor
val jobs = Array(asyncFactor) { idx ->
async(Dispatchers.Default) {
val chunkStartIdx = chunkSize * idx
val chunkEndIdxExclusive = min(chunkStartIdx + chunkSize, dst.sizeBytes)
calculateSampledImageForIndexes(src, dst, chunkStartIdx, chunkEndIdxExclusive, SCALE)
}
}
awaitAll(*jobs)
}
private fun calculateSampledImageForIndexes(src: Image, dst: Image, startIdx: Int, exclusiveEndIdx: Int, scaleFactor: Int) {
for (i in startIdx until exclusiveEndIdx) {
val destX = i % dst.width
val destY = i / dst.width
val srcX = destX * scaleFactor
val srcY = destY * scaleFactor
var sum = 0
for (xi in 0 until scaleFactor) {
for (yi in 0 until scaleFactor) {
sum += src[srcX + xi, srcY + yi]
}
}
dst[destX, destY] = sum / (scaleFactor * scaleFactor)
}
}
Where Image is a convenient wrapper around the image data buffer:
class Image(val buffer: ByteArray, val width: Int) {
val height = buffer.size / width
val sizeBytes get() = buffer.size
constructor(w: Int, h: Int) : this(ByteArray(w * h), w)
operator fun get(x: Int, y: Int): Byte = buffer[clampX(x) * width + clampY(y)]
operator fun set(x: Int, y: Int, value: Int) {
buffer[x * width + y] = (value and 0xFF).toByte()
}
private fun clampX(x: Int) = max(min(x, width), 0)
private fun clampY(y: Int) = max(min(y, height), 0)
}
Also, with this approach you can easily implement many image processing functions, which based on convolution operation, like blur and edge detection.

Avoiding explicit record typing

Suppose I have the following functions for operating over an idealized stream:
fun Stream s = { pos = 0, row = 1, col = 0, str = s }
fun len { str, pos = _, row = _, col = _ } = String.size str
fun poke off { str, pos, row: int, col: int } =
let val n = pos + off in
if n >= 0 andalso n <= (String.size str) then SOME (String.sub(str, n)) else NONE
end
This works/compiles, but it's unfortunate to have to litter my function definitions with information I don't care about. row/col are ignored poke and len. However, while the wildcard can be used with len, it can't be with poke. Is there a way to restructure these functions so that less explicit typing needs to be put in, while still being able to pattern match/destructure?
If you give your type a name (such as stream), you can refer to it more briefly:
type stream = { pos : int, row : int, col : int, str : string }
fun Stream s = { pos = 0, row = 1, col = 0, str = s }
fun len ({ str, ... } : stream) = String.size str
fun poke off ({ str, pos, ... } : stream) =
let val n = pos + off in
if n >= 0 andalso n <= String.size str
then SOME (String.sub (str, n))
else NONE
end
Or, more-or-less equivalently:
datatype stream = STREAM of { pos : int, row : int, col : int, str : string }
fun Stream s = STREAM { pos = 0, row = 1, col = 0, str = s }
fun len (STREAM { str, ... }) = String.size str
fun poke off (STREAM { str, pos, ... }) =
let val n = pos + off in
if n >= 0 andalso n <= String.size str
then SOME (String.sub (str, n))
else NONE
end

Scala, position objects on a circumference

I am trying to populate a circumference with points located at equal intervals. Here is the code (it uses some Processing, but it is not crucial for understanding):
class Circle (x: Float, y: Float, subdivisions: Int, radius: Float) extends WorldObject(x, y) {
def subs = subdivisions
def r = radius
val d = r + r
def makePoints() : List[Glyph] = {
val step = PConstants.TWO_PI / subdivisions
val points = List.make(subdivisions, new Glyph())
for(i <- 0 to subdivisions - 1) {
points(i) position (PApplet.cos(step * i) * r + xPos, PApplet.sin(step * i) * r + yPos)
}
points
}
val points: List[Glyph] = makePoints()
override def draw() {
applet fill 0
applet stroke 255
applet ellipse(x, y, d, d)
applet fill 255
points map(_.update())
}
}
class Glyph(x: Float, y: Float) extends WorldObject(x, y){
def this() = this(0, 0)
override def draw() {
applet ellipse(xPos, yPos, 10, 10)
}
}
object WorldObject {
}
abstract class WorldObject(var xPos: Float, var yPos: Float) {
def this() = this(0, 0)
def x = xPos
def y = yPos
def update() {
draw()
}
def draw()
def position(x: Float, y: Float) {
xPos = x
yPos = y
}
def move(dx: Float, dy: Float) {
xPos += dx
yPos += dy
}
}
The strange result that I get is that all the points are located at a single place. I have experimented with println checks... the checks in the makePoints() method shows everything ok, but checks in the Circle.draw() or even right after the makePoints() show the result as I see it on the screen - all points are located in a single place, right where the last of them is generated, namely x=430.9017 y=204.89435 for a circle positioned at x=400 y=300 and subdivided to 5 points. So somehow they all get collected into the place where the last of them sits.
Why is there such a behavior? What am I doing wrong?
UPD: We have been able to locate the reason, see below:
Answering the question, user unknown changed the code to use the fill method instead of make. The main relevant difference between them is that make pre-computes it's arguments and fill does not. Thus make fills the list with totally identical items. However, fill repeats the computation on each addition. Here are the source codes of these methods from Scala sources:
/** Create a list containing several copies of an element.
*
* #param n the length of the resulting list
* #param elem the element composing the resulting list
* #return a list composed of n elements all equal to elem
*/
#deprecated("use `fill' instead", "2.8.0")
def make[A](n: Int, elem: A): List[A] = {
val b = new ListBuffer[A]
var i = 0
while (i < n) {
b += elem
i += 1
}
b.toList
}
And the fill method:
/** Produces a $coll containing the results of some element computation a number of times.
* #param n the number of elements contained in the $coll.
* #param elem the element computation
* #return A $coll that contains the results of `n` evaluations of `elem`.
*/
def fill[A](n: Int)(elem: => A): CC[A] = {
val b = newBuilder[A]
b.sizeHint(n)
var i = 0
while (i < n) {
b += elem
i += 1
}
b.result
}
I changed a lot of variables forth and back (def x = ... => def x () = , x/ this.x and x/xPos and so on) added println statements and removed (P)applet-stuff, which made the compiler complain.
Providing a compilable, runnable, standalone demo would be beneficial. Here it is:
class Circle (x: Float, y: Float, subdivisions: Int, radius: Float)
extends WorldObject (x, y) {
def subs = subdivisions
def r = radius
val d = r + r
def makePoints() : List[Glyph] = {
// val step = PConstants.TWO_PI / subdivisions
val step = 6.283F / subdivisions
val points = List.fill (subdivisions) (new Glyph ())
for (i <- 0 to subdivisions - 1) {
// points (i) position (PApplet.cos (step * i) * r + xPos,
// PApplet.sin (step * i) * r + yPos)
val xx = (math.cos (step * i) * r).toFloat + xPos
val yy = (math.sin (step * i) * r).toFloat + yPos
println (xx + ": " + yy)
points (i) position (xx, yy)
}
points
}
val points: List [Glyph] = makePoints ()
override def draw () {
/*
applet fill 0
applet stroke 255
applet ellipse(x, y, d, d)
applet fill 255
*/
// println ("Circle:draw () upd-> " + super.x () + "\t" + y () + "\t" + d);
points map (_.update ())
println ("Circle:draw () <-upd " + x + "\t" + y + "\t" + d);
}
}
class Glyph (x: Float, y: Float) extends WorldObject (x, y) {
def this () = this (0, 0)
override def draw() {
// applet ellipse (xPos, yPos, 10, 10)
println ("Glyph:draw (): " + xPos + "\t" + yPos + "\t" + 10);
}
}
object Circle {
def main (as: Array [String]) : Unit = {
val c = new Circle (400, 300, 5, 100)
c.draw ()
}
}
object WorldObject {
}
abstract class WorldObject (var xPos: Float, var yPos: Float) {
def this () = this (0, 0)
def x = xPos
def y = yPos
def update () {
draw ()
}
def draw ()
def position (x: Float, y: Float) {
xPos = x
yPos = y
// println (x + " ?= " + xPos + " ?= " + (this.x ()))
}
def move (dx: Float, dy: Float) {
xPos += dx
yPos += dy
}
}
My result is:
500.0: 300.0
430.9052: 395.1045
319.10266: 358.78452
319.09177: 241.23045
430.8876: 204.88977
Glyph:draw (): 500.0 300.0 10
Glyph:draw (): 430.9052 395.1045 10
Glyph:draw (): 319.10266 358.78452 10
Glyph:draw (): 319.09177 241.23045 10
Glyph:draw (): 430.8876 204.88977 10
Circle:draw () <-upd 400.0 300.0 200.0
Can you spot the difference?
You should create a copy of your code, and stepwise remove code, which isn't necessary to reproduce the error, checking, whether the error is still present. Then you should reach a much smaller problem, or find the error yourself.