generate random numbers truncated to 2 decimal places
Solution 1
A float
cannot be truncated (or rounded) to 2 decimal digits, because there are many values with 2 decimal digits that just cannot be represented exactly as an IEEE double.
If you really want what you say you want, you need to use a type with exact precision, like Decimal
.
Of course there are downsides to doing that—the most obvious one for numpy
users being that you will have to use dtype=object
, with all of the compactness and performance implications.
But it's the only way to actually do what you asked for.
Most likely, what you actually want to do is either Joran Beasley's answer (leave them untruncated, and just round at print-out time) or something similar to Lauritz V. Thaulow's answer (get the closest approximation you can, then use explicit epsilon checks everywhere).
Alternatively, you can do implicitly fixed-point arithmetic, as David Heffernan suggests in a comment: Generate random integers between 0 and 50, keep them as integers within numpy
, and just format them as fixed point decimals and/or convert to Decimal
when necessary (e.g., for printing results). This gives you all of the advantages of Decimal
without the costs… although it does open an obvious window to create new bugs by forgetting to shift 2 places somewhere.
Solution 2
How about this?
np.random.randint(0, 50, size=(50,1)).astype("float") / 100
That is, create random integers between 0 and 50, and divide by 100.
EDIT:
As made clear in the comments, this will not give you exact two-digit decimals to work with, due to the nature of float representations in memory. It may look like you have the exact float 0.1
in your array, but it definitely isn't exactly 0.1
. But it is very very close, and you can get it closer by using a "double" datatype instead.
You can postpone this problem by just keeping the numbers as integers, and remember that they're to be divided by 100 when you use them.
hundreds = random.randint(0, 50, size=(50, 1))
Then at least the roundoff won't happen until at the last minute (or maybe not at all, if the numerator of the equation is a multiple of the denominator).
Solution 3
decimals are not truncated to 2 decimal places ever ... however their string representation maybe
import numpy as np
rs = np.random.RandomState(123456)
set = rs.uniform(size=(50,1))*0.5
print ["%0.2d"%val for val in set]
Comments
-
mtigger almost 2 years
I would like to generate uniformly distributed random numbers between 0 and 0.5, but truncated to 2 decimal places.
without the truncation, I know this is done by
import numpy as np rs = np.random.RandomState(123456) set = rs.uniform(size=(50,1))*0.5
could anyone help me with suggestions on how to generate random numbers up to 2 d.p. only? Thanks!
-
Lauritz V. Thaulow almost 11 years@Joran Wow, that's fast feedback. Have you tested this? My tests all return only two or one decimal places.
-
abarnert almost 11 years@LauritzV.Thaulow: There are many values with two decimal places that cannot be represented exactly as a float (IEEE double). So, you may get the closest float to the value you wanted, and it may even
repr
andstr
as the value you wanted… but when you do arithmetic with it, or just compare it with==
, it may not be the value you wanted. You have to use an exact-precision type likeDecimal
if you really want two decimal places. -
abarnert almost 11 years
Decimal
s can be truncated to 2 decimal places; it'sfloat
s that can't. -
aestrivex almost 11 yearsAlso, this doesn't solve the problem because sampling from a normal distribute won't generate integers (though you could round the distribution so it does). A more general idea of a solution along these lines would be (for x~Norm(params)),
int(round(x*100))/100
. -
Joran Beasley almost 11 yearsmeh semantics :P (but yeah I know Decimal is an exact representation type :P)
-
mtigger almost 11 yearsthank you, this cleared up some misconceptions I had about floats and decimals.
-
abarnert almost 11 years@mtigger: Here's the obligatory link to What Every Computer Scientist Should Know About Floating-Point Arithmetic.
-
Lauritz V. Thaulow almost 11 yearsWhy not just use
np.around(rs.uniform(size=(50,2)) * 0.5, decimals=2)
then? It's faster, it works the same, and has the same technical drawback that my solution has, as noted in the docs: Results may also be surprising due to the inexact representation of decimal fractions in the IEEE floating point standard.