0

I need a function that returns me a random number with n decimal places Example:

int aleatorio(int li, int ls)
{
    return rand()%(ls+1-li)+li;
}

What i want is:

float new_random(int start, int final, int number_decimals)
{
    return // What should I write here?
}

if I would call this function 5 times like this::

new_random(0, 5, 4);

The exit would be:

0.2344
 
3.4356

2.8435

4.2435

I do not want to use this, because I need numbers of 4 exact decimal places since I will not use them to print, but you will have others:

cout << setprecision(4) << 4.24359675967 << endl; //I do not want this
Filburt
  • 17,626
  • 12
  • 64
  • 115
Pxnditx YR
  • 79
  • 1
  • 10

3 Answers3

1

I need numbers of 4 exact decimal places

Then you cannot use finite precision binary floating point (i.e. float, double or long double) because those types cannot exactly represent all of the values with 4 decimal places.

A solution is to use arbitrary precision floating point, and another is to use fixed point. C++ standard doesn't provide arbitrary precision types nor fixed point types. Another approach is to give up the requirement of exactly representing those values and accept the almost exact values that are achievable with limited precision.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • ... and here's an example to show what the lack of arbitrary precision in floating point types means for the random numbers: https://godbolt.org/z/553MPe – Ted Lyngmo Nov 04 '20 at 23:01
0

Try this for a Java solution. Multiply the start and finish by 1000, generating ints between the range and then divide the resultant number by 1000 as a double.

int start = 20;
int finish = 30;
int count = 10;

Random r = new Random();

r.ints(start * 1000, finish * 1000).filter(n -> n % 10 != 0)
        .limit(count).mapToDouble(n -> n / 1000.)
        .forEach(System.out::println);

prints something like this.

21.186
26.983
25.345
20.764
27.911
21.139
24.679
27.722
29.443
28.675

Or as a method supplying the starting number, ending number and precision.

for (int i = 0; i < 10; i++) {
        System.out.println(newRandom(start,finish,4));
}
    
static Random r = new Random();
public static Double newRandom(int start, int finish, int precision) {
        int f = (int)Math.pow(10,precision);
        return r.ints(start * f, finish * f).filter(n -> n % 10 != 0)
        .limit(1).mapToDouble(n -> n / (double)f).findFirst().getAsDouble();
}

Prints something like this.

28.4444
25.0259
29.5611
25.6445
25.4977
28.5124
28.9709
23.4835
27.9766
23.9438
        
    
WJS
  • 36,363
  • 4
  • 24
  • 39
  • Unless you use `java.math.BigDecimal` this won't be exact either if I understand it correctly. – Ted Lyngmo Nov 04 '20 at 23:18
  • Unless the denominator consists solely of powers of 2 and/or 5 no floating point fraction will be exact because they will all be repeating and rounded appropriately upon print out. but I don't really think that is what the OP intended. If they start comparing these values to others with no delta of accuracy they will be in for a rude awakening – WJS Nov 04 '20 at 23:40
  • I interpret "_I need numbers of 4 exact decimal places since I will not use them to print_" like OP indeed wants exactly 4 decimals. – Ted Lyngmo Nov 04 '20 at 23:55
0

You can generate an integer number N between start and final * 10^number_decimals and then return N / 10^number_decimals

Eg. start = 0, final = 5, number_decimals = 4 ==> N in [0 - 50000] ==> N/10000 in [0.0000 - 5.0000]

float new_random(int start, int final, int number_decimals) {
    return aleatorio(start, final*pow10(number_decimals))/number_decimals; 
}

You can define pow10 as:

int pow10(int p) {
  if (p == 0) return 1;
  else return 10 * pow10(p-1);
}
Stefano
  • 23
  • 5
  • 1
    Better test that `pow10` function. Looks like the results will be downright comical if `p` isn't 0 or 1. – user4581301 Nov 04 '20 at 22:49
  • 1
    @user4581301 :-) [this](https://stackoverflow.com/a/18581693/7582247) would be a better `pow10` option. – Ted Lyngmo Nov 04 '20 at 22:50
  • @user4581301 you're absolutely right! I changed the code to fix the problem. Thanks, also to Ted Lyngmo for suggesting better implementations (but that was not the purpose of my answer) – Stefano Nov 05 '20 at 10:20
  • Of course I saw that possibility, but I separate integers and decimals because if I want a number from 0 to 5 there are 1/5 probabilities for the whole number, and 4 decimals 1/9999 probabilities @Stefano – Pxnditx YR Nov 05 '20 at 21:21