Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rounding to specific number of digits in Haskell

Tags:

math

haskell

I am trying to make a function to round a floating point number to a defined length of digits. What I have come up with so far is this:

import Numeric;

digs :: Integral x => x -> [x] <br>
digs 0 = [] <br>
digs x = digs (x `div` 10) ++ [x `mod` 10]

roundTo x t = let d = length $ digs $ round x <br>
                  roundToMachine x t = (fromInteger $ round $ x * 10^^t) * 10^^(-t)
              in roundToMachine x (t - d)

I am using the digs function to determine the number of digits before the comma to optimize the input value (i.e. move everything past the comma, so 1.234 becomes 0.1234 * 10^1)

The roundTo function seems to work for most input, however for some inputs I get strange results, e.g. roundTo 1.0014 4 produces 1.0010000000000001 instead of 1.001.

The problem in this example is caused by calculating 1001 * 1.0e-3 (which returns 1.0010000000000001)

Is this simply a problem in the number representation of Haskell I have to live with or is there a better way to round a floating point number to a specific length of digits?

like image 322
Philipp Avatar asked Sep 10 '13 15:09

Philipp


People also ask

How do you round a number in Haskell?

You can get approximately what you want by multiplying by 1e6 , rounding to the nearest integer, and dividing by 1e6 .

How do you round to digits?

Rounding is a process to estimate a particular number in a context. To round a number look at the next digit in the right place, if the digit is less than 5, round down and if the digit is 5 or more than 5, round up.

How do you round 5 digits?

If the digit is a five or greater, you round the target digit up by one. Otherwise, you leave the target as it is. Then you replace any digits to the right with zeroes (if they are to the left of the decimal point) or else you delete the digits (if they are past the decimal point).

How do you round to the least precise number?

Rounding Addition You would add (or subtract) the numbers as usual, but then you would round the answer to the same decimal place as the least-accurate number.


1 Answers

I realise this question was posted almost 2 years back, but I thought I'd have a go at an answer that didn't require a string conversion.

-- x : number you want rounded, n : number of decimal places you want...
truncate' :: Double -> Int -> Double
truncate' x n = (fromIntegral (floor (x * t))) / t
    where t = 10^n

-- How to answer your problem...
λ truncate' 1.0014 3
1.001

-- 2 digits of a recurring decimal please...
λ truncate' (1/3) 2
0.33

-- How about 6 digits of pi?
λ truncate' pi 6
3.141592

I've not tested it thoroughly, so if you find numbers this doesn't work for let me know!

like image 153
schanq Avatar answered Sep 26 '22 21:09

schanq