Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the optimal way of representing a floating point number in a range from 0 to 1?

I'm looking for a numeric type able to represent, say, a value 0.213123 or 0.0, or 1.0, but refusing the out of range values, such as -0.2123 and 1.2312. Does there exist a specific type fitting that purpose, and what is the optimal general approach to restricting numbers to a specific range?

Of course, the first answer coming to mind is: just use Double, but getting spoiled by Haskell's type system I've gotten used to maximally securing the program on a type level.

like image 823
Nikita Volkov Avatar asked Feb 22 '13 18:02

Nikita Volkov


People also ask

How many floating point numbers are there between 0 and 1?

So how many “normal” non-zero numbers are there between 0 and 1? The negative exponents range from -1 all the way to -126. In each case, we have 223 distinct floating-point numbers because the mantissa is made of 23 bits. So we have 126 x 223 normal floating-point numbers in [0,1).

What is the range of the floating point numbers?

A single-precision, floating-point number is a 32-bit approximation of a real number. The number can be zero or can range from -3.40282347E+38 to -1.17549435E-38, or from 1.17549435E-38 to 3.40282347E+38.

Is 1 a floating-point number?

A Floating Point number usually has a decimal point. This means that 0, 3.14, 6.5, and -125.5 are Floating Point numbers.


Video Answer


2 Answers

A Serious Suggestions

You could use a newtype wrapper (and smart constructor) around a word of the proper bit size:

newtype SmallFrac = SF Word64

-- Example conversion (You'd actually want to make
-- instances of common classes, I assume)
sfToDouble :: SmallFrac -> Double
sfToDouble (SF x) = fromIntegral x / fromIntegral (maxBound `asTypeOf` x)

instance Show SmallFrac where
    show = show . sfToDouble

Implementing multiplication and division might be more costly than you would like, but at least addition is easy (modulo protecting against over/underflow) and you claim to not need any operations so even better.

A Less Useful Suggestion

If all you need is a symbol representing a value exists between one and zero then take dave4420's suggestion and just have a unit type:

newtype SmallFrac = SF ()

There are no operations for this type, not even conversion to/from other types of interest such as Double, but this meets the request as stated.

like image 143
Thomas M. DuBuisson Avatar answered Oct 09 '22 10:10

Thomas M. DuBuisson


Not standard. You'd have to make one -- I'd suggest a smart constructor. Keep in mind though that such a type supports very few numeric operations -- you can't add them and keep them in the set, nor negate them, so I would advise against a Num instance. A Monoid on multiplication would be reasonable.

like image 4
luqui Avatar answered Oct 09 '22 11:10

luqui