In Java, I need to randomly generate a number between 0 and 0.06.
I saw on another question on here that the following code would do the trick:
Random generator = new Random();
double number = generator.nextDouble() * .06;
However, doing that gives me really long numbers like 0.007044013589130205 and 0.03656588431980957, which I don't think is what my instructor is looking for.
Is there anyway to generate random numbers between 0 and 0.06 that only have two or three decimal places?
If you want a number that ranges between [0 - 0.06] with a difference of 0.01, you can do the following:
Random generator = new Random();
int number = generator.nextInt(7);
double result = number / 100.0;
You can generalize the formula to number = generator.nextInt(max - min + 1) + min; where max and min will be the highest and the lowest number that you what to generate, respectively. This will generate a number from [min to max+1].
To increase the decimal places of the generated number one just has to divide that number by the appropriate power of 10 (e.g., 1000, 10000, ...)
Internally, Java double values are a binary floating point representation. They don't have decimal places. You can format a double as a base-10 number string having a specified number of decimal places. For example, to get three decimals (precision 0.001), you could use:
String formatted = String.format("%.3f", number);
If you don't need to do any calculations with the number and you want two or three decimal places, just print 0.0 and then a two-digit random integer between 00 and 60 (inclusive).
I assume you need precision to be 0.001, so try this:
Random r = new Random();
int ret = r.nextInt(60 + 1);
return ret / 1000.0;
this will generate [0,0.060] averagely with difference multiple of 0.001,that may be your want
Since you're dealing with sales tax, you should be aware of Why not use Double or Float to represent currency? and Using BigDecimal to work with currencies
To generate a random BigDecimal with constraints on range and # of significant digits, see How can I create a random BigDecimal in Java?
Related
How do I implement a function getRandomDouble(min,max) which is able to handle +-Double.MAX_VALUEas parameter?
Online Research:
Most answers to this question are:
public Double getRandomDouble(double min, double max) {
return min + (max-min)*Random.nextDouble();
}
This works fine if min and max are not +-Double.MAX_VALUE. If so, max-min is out of range or infinity. Changing the parameters to BigDecimal solves this issue, but the result is always a double with 50 zeros and no decimals. This is the result of a very large number (2*MAX_VALUE) multiplied a double between [0,1] with only a view decimals.
So, I found a solution for +-MAX_VALUE like this:
public double getRandomDouble() {
while(true) {
double d = Double.longBitsToDouble(Random.nextLong());
if (d < Double.POSITIVE_INFINITY && d > Double.NEGATIVE_INFINITY)
return d;
}
}
This works fine, but does not consider other bounds.
How can I combine both approaches to get random double in a given range that's maybe +-MAX_VALUE?
If it's not working only with the max values, I think I have a solution.
Mathematically it should be the same:
You produce 2 random numbers and sum them up. Each number should be between -maxValue / 2 and +maxValue / 2. That way the sum will be a random number between -maxValue and +maxValue.
public Double getRandomDouble(double min, double max) {
double halfMin = min/2;
double halfMax = max/2;
double sum = halfMin + (halfMax-halfMin)*Random.nextDouble();
return sum + (halfMin + (halfMax-halfMin)*Random.nextDouble());
}
You can do this by drawing two double random numbers. The first one is used to decide if you want a negative value or a positive value. The second one is used for the actual value from the negative part or the positive part. The approach will be like this:
Calculate the quotient between the range from zero to upper bound and the range from zero to lower bound. This will get you the information like "40% the value is positive, 60% the value is negative". Use the first random number to check which it is.
Then when you know if it is negative or positive use the normal approach to get a random number between zero and the lower/upper bound. This value can only be between 0 and MAX_VALUE (or MIN_VALUE), so there will be no "overflow".
However, I don't know about the combined probability in this case, if it is the same random probability when drawing only one random double value. If you have a negative/positive split of about 5% and 95%, then the second random number will be hit a value inside the 5% or the 95%. Not sure if it still "random" or if it even creates unwanted bias.
I'm trying to understand the scale for a BigDecimal but it acts weird and I can't understand why. Here's a couple of examples:
Double d = new Double(1000000d);
int scale = new BigDecimal(d.toString()).scale();
The scale in this example will be 1 which is correct to me.
The result of d.toString() is "1000000.0".
Double d = new Double(10000000d);
int scale = new BigDecimal(d.toString)).scale();
The scale in this example will be -6. Can anyone explain why?
The result of d.toString() is "1.0E7".
I thought the number of digits caused this but if I go:
Double d = new Double(11111111d);
int scale = new BigDecimal(d.toString()).scale();
Expected a scale of -8 but suddenly it's 0.
The result of d.toString() is "1.1111111E7".
These different scales make no sense to me after reading the Javadoc of scale():
Returns the scale of this BigDecimal. If zero or positive, the scale is the number of digits to the right of the decimal point. If negative, the unscaled value of the number is multiplied by ten to the power of the negation of the scale. For example, a scale of -3 means the unscaled value is multiplied by 1000.
I'd very much appreciate an explanation how BigDecimal behaves when the numbers are large.
Thanks in advance!
The scale you got is the number of decimals with some significance:
1000000d -> 1000000.0 -> 0: the numbers at the right of the dot have no significance, the result is 0;
10000000d -> 1.0E7 -> -6: the numbers at the right of the dot have significance, as if you denormalize the power by ten you get the 6 zeros;
11111111d -> 1.1111111E7 -> 0: all the numbers at the right of the dot have significance, denormalizing the power by ten you get more information, so you "can't" normalize the number if you want to keep this information. This way (the number denormalized), you have 0 numbers at the right of the dot.
EDIT
As commented, the first line is wrong, it must be 1000000d -> 1000000.0 -> 1. The reason is that the numbers with exponential have a different behavior (when obtaining the scale) that the formatted numbers.
The value of 1 is due that BigDecimal counts the numbers in the right side of the dot (which in this case is one, a single 0), subtract the numbers to drop (in this case there is one, the single 0) and add the math precision (by default is one) -> result = 1.
You are seeing the behavior your report because you are calling toString() on the decimal provided, which in for some of your examples represents in exponential notation, which is then preserved by BigDecimal when it chooses the scale.
If you provide the the double directly to the BigDecimal constructor you consistently get 0.
new Double(1000000d).toString() //1.0E7
Double d = new Double(1000000d);
int scale = new BigDecimal(d).scale(); //0
Double d = new Double(10000000d);
int scale = new BigDecimal(d).scale(); //0
Double d = new Double(11111111d);
int scale = new BigDecimal(d).scale(); //0
Update:
scale is is not a useful attribute on its own. It must be considered in conjunction with unscaledValue. The represented number is unscaledValue × 10 ^ -scale.
That is,
BigDecimal d = new BigDecimal(1000000d)
BigDecimal e = d.setScale(2)
int dScale = d.scale() //0
int dUnscaled = d.unscaledValue() //1000000
int eScale = e.scale() //2
int eUnscaled = e.unscaledValue() //100000000
Both d and e are a representation of 1000000. However, e preserves there are 2 trailing zeros (zeros after the decimal point).
d.toString() //1000000
e.toString() //1000000.00
This question already has an answer here:
Generate numbers that divide evenly [closed]
(1 answer)
Closed 6 years ago.
I have to create a method that generates randomly 2 numbers, that divided give as result a number without decimals.
For example:
int result = 4 / 2; //is ok
int result = 4 / 3; //is NOT ok
I already create a recursive method that, when the result is a decimal number, call itself and generates 2 new numbers. But, of course, this is not the best approach since, in theory, I may get as a result a decimal number forever!
Is there a good way to achieve my goal?
Why not generate the result and divisor, then multiply both to get the dividend?
Instead of using 4 and 3 as dividend and divisor, which results in a decimal number when divided, multiply them both to get 12 as dividend and 4 as divisor which once divided gives 3.
when numerator/denominator = result, then numerator= result x denominator
then it will be easier to gen result and denominator :)
int numerator;
int denominator;
int result;
result= rand.nextInt(5,10);
denominator= rand.nextInt(2,10);
numerator = result * denominator;
The below algorithm works to identify a factor of a small number but fails completely when using a large one such as 7534534523.0
double result = 7; // 7534534523.0;
double divisor = 1;
for (int i = 2; i < result; i++){
double r = result / (double)i;
if (Math.floor(r) == r){
divisor = i;
break;
}
}
System.out.println(result + "/" + divisor + "=" + (result/divisor));
The number 7534534523.0 divided by 2 on a calculator can give a decimal part or round it (losing the 0.5). How can I perform such a check on large numbers? Do I have to use BigDecimal for this? Or is there another way?
If your goal is to represent a number with exactly n significant figures to the right of the decimal, BigDecimal is the class to use.
Immutable, arbitrary-precision signed decimal numbers. A BigDecimal consists of an arbitrary precision integer unscaled value and a 32-bit integer scale. If zero or positive, the scale is the number of digits to the right of the decimal point. If negative, the unscaled value of the number is multiplied by ten to the power of the negation of the scale. The value of the number represented by the BigDecimal is therefore (unscaledValue × 10-scale).
Additionally, you can have a better control over scale manipulation, rounding and format conversion.
I don't see what the problem is in your code. It works exactly like it should.
When I run your code I get this output:
7.534534523E9/77359.0=97397.0
That may have confused you, but its perfectly fine. It's just using scientific notation, but there is nothing wrong with that.
7.534534523E9 = 7.534534523 * 109 = 7,534,534,523
If you want to see it in normal notation, you can use System.out.format to print the result:
System.out.format("%.0f/%.0f=%.0f\n", result, divisor, result / divisor);
Shows:
7534534523/77359=97397
But you don't need double or BigDecimal to check if a number is divisible by another number. You can use the modulo operator on integral types to check if one number is divisible by another. As long as your numbers fit in a long, this works, otherwise you can move on to a BigInteger:
long result = 7534534523L;
long divisor = 1;
for (int i = 2; i < result; i++) {
if (result % i == 0) {
divisor = i;
break;
}
}
System.out.println(result + "/" + divisor + "=" + (result / divisor));
BigDecimal is the way to move ahead for preserving high precision in numbers.
DO NOT do not use constructor BigDecimal(double val) as the rounding is performed and the output is not always same. The same is mentioned in the implementation as well. According to it:
The results of this constructor can be somewhat unpredictable. One might assume that writing new BigDecimal(0.1) in Java creates a BigDecimal which is exactly equal to 0.1 (an unscaled value of 1, with a scale of 1), but it is actually equal to 0.1000000000000000055511151231257827021181583404541015625. This is because 0.1 cannot be represented exactly as a double (or, for that matter, as a binary fraction of any finite length). Thus, the value that is being passed in to the constructor is not exactly equal to 0.1, appearances notwithstanding.
ALWAYS try to use constructor BigDecimal(String val) as it preserves precision and gives same output each time.
I'm trying to calculate a percentage "factor". That is, given a 20%, convert it into 0.2 (my intention is to later multiply values by that and get the 20% of the values).
Anyway, the question is related with this piece of code:
public static void main(String[] args) {
int roundingMode = BigDecimal.ROUND_FLOOR;
BigDecimal hundred = new BigDecimal("100");
BigDecimal percentageFactor = null;
BigDecimal percentage = new BigDecimal("20");
BigDecimal value = new BigDecimal("500");
percentageFactor = percentage.divide(hundred, roundingMode);
float f = percentage.floatValue() / hundred.floatValue();
f = value.floatValue() * f;
BigDecimal aux = value.multiply(percentageFactor);
System.out.println("factor:"+percentageFactor.toString());
System.out.println("final falue:"+aux.toString());
System.out.println("Float Value:"+f);
}
I would expect the outcome of this to be something like:
factor: 0.2
final value: 100
float value: 100
but instead percentage.divide(hundred, roundingMode); is returning zero, an hence I get:
factor:0
final falue:0
Float Value:100.0
What am I doing wrong? How can I divide two big decimals properly?
By the way, I'm using BigDecimal because I will be calculating monetary percentages, so I want control regarding rounding.
I think that the best solution is to set the requested scale when dividing: In this case perhaps 2.
var hundred = new BigDecimal(100);
var percentage = new BigDecimal(20);
var value = new BigDecimal(500);
var percentageFactor =
percentage.divide(hundred,2, BigDecimal.ROUND_HALF_UP);
value = value.multiply(percentageFactor);
System.out.println("final value:"+ value);
Final value: 100.00
The multiplication is using the scale from the factors (0+2) but it can be specified too.
I'd use ROUND_HALF_UP for accounting (in my legislation) or ROUND_EVEN (for statistics) for rounding mode.
The scale of new BigDecimal("20") is zero because you've got no decimal point in there. That means that your percentage.divide(hundred, BigDecimal.ROUND_FLOOR) will produce zero (it's effectively int(20/100) or 0).
If you really want to do fractional stuff, use new BigDecimal("20.00") so the scale is set correctly, or use one of the other constructors to set the scale specifically.
Here's the output from that simple change of 20 to 20.00, complete with your spellink misteak :-)
factor:0.20
final falue:100.00
Float Value:100.0
float has only 6 digits of accuracy and is almost never a good choice, I would suggest you use double instead. (or BigDecimal can be better in some cases)
The reason factor is 0 instead of 0.2 in your code is because
you've set the RoundingMode to be FLOOR (which means ROUND DOWN), and
your percentage variable has an implicit scale of 0 (any BigDecimals initialised from round number without specifying scale will have scale of 0)
So when you call divide you are rounding down any decimals and you are maintaining a scale of 0, and hence 0.2 is rounded down to 0.
To get the correct number, you can either
specify the scale explicitly, or
since you know you are dividing against 100, you can just use the BigDecimal#divide(BigDecimal) method instead (without providing scale or RoundingMethod). In your case, the method will not throw ArithmeticException since there is no possibility of non-terminating decimals (think 20 / 100 = 0.2, 20 / 10000 = 0.002 - decimals always terminate when dividing by 100).
However, if you're dividing against another number say 3 then you need to specify the scale because there is a possibility of non-terminating decimals (think 10 / 3 = 3.3333333333...)