Как генерировать случайные числа, которые обеспечат надлежащие результаты при делении

#java #math #decimal

#java #математика #десятичная

Вопрос:

Как генерировать случайные числа, которые обеспечат надлежащие результаты при делении (т. е. Результаты должны округляться ровно до 1 или 2 знаков после запятой).

(например, целое число с десятичным числом, обеспечивающее десятичные результаты — я привел набор примеров входных данных ниже)

 2827 by 2.5 = 1130.8
1747 by 0.8 = 2183.75
425 by 0.4 = 1062.5
935 by 0.8 = 1168.75
  

Комментарии:

1. Каким должен быть диапазон делителей и дивидендов?

2. Это не ответ, поэтому я публикую его в качестве комментария, но убедитесь, что вы понимаете этот документ, поскольку это может повлиять на ваше решение: download.oracle.com/docs/cd/E19957-01/806-3568 /…

3. Какие числа здесь являются случайными — делители или дивиденды? Если вам нужно ровно 1 или 2 знака после запятой, почему вы не можете просто работать с целыми числами и позже разделить на 100?

4. как насчет генерации результата и идентификатора devidor и генерации третьего из них? это немного обман, но это может решить проблему :

5. @Matt: Я думаю: Если вы разделите 1 на 3, вы получите 0,3333… — Если вы разделите 100/3, вы получите 33.3333… . Вы предлагаете использовать целочисленное деление (100/3 = 33), а затем разделить на 100 => (0.33), но в итоге всегда возникают проблемы с округлением. .33 * 3 равно .99. 33/100 равно 0.33. Он ищет не метод округления, а правильные делители для (числа, умноженного на 100).

Ответ №1:

 res = input * random.nextInt (100) / 100.0;
  

Объяснение:

Вы берете целое число n и умножаете его на что-то. Если это что-то является числом, подобным 34.56, мы вызываем часть перед десятичной цифрой w (целая часть) и часть после .xy.

Если вы умножите это на n, в итоге получится (n * w) (n * (x / 10)) n * (y / 100). За точкой никогда не будет дробной части 3-х шифров — вы согласны?

Мы можем объединить x и y в одну часть и сказать (n * w) (n * (xy / 100)), а xy — это просто название для чего-то от 0 до 100.

Поскольку часть перед десятичной точкой может быть произвольно большой, вы можете вычислить ее отдельно, если вам нужно что-то еще, кроме 0. Но вы должны каким-то образом определить диапазон. Если вы возьмете случайное целое число R для этой части:

 res = input * R * random.nextInt (100) / 100.0;
  

Вам нужен divisor explicityl?

 div = 100.0 / (R * random.nextInt (100));
  

Scala всегда удобен при тестировании фрагментов кода:

 val r = util.Random 
r: util.Random.type = scala.util.Random$@ce2f12

scala> def res (input: Int) = input * r.nextInt (100) / 100.0;
res: (input: Int)Double

scala> (1 to 20).map (res) 
res338: scala.collection.immutable.IndexedSeq[Double] =
Vector(0.48, 1.58, 0.48, 2.8, 0.15, 1.98, 5.67, 3.36, 6.93, 6.0, 9.02, 0.48, 7.41, 6.44, 9.6, 1.92, 16.66, 5.94, 7.98, 18.4)
  

Ответ №2:

Стоит отметить, что все целые числа можно разделить на 0,4, 0,8 или 2,5 и представить с точностью до двух знаков после запятой. Это потому, что это то же самое, что умножение на 2.5, 1.25 и 0.4


Однако, если у вас есть делитель, для которого это неверно, вы можете сделать это в цикле.

 double divisor = 2.4;
double factor = 100/divisor;
Random rand = new Random();
int maxValue = 1000;
double ERROR = 1e-14*maxValue;

for(int i=0;i<100;i  ) {
long randNum;
do {
   randNum = rand.nextInt(maxValue 1);
    if (Math.abs(randNum * factor - (long) (randNum * factor)) > ERROR)
        System.out.println("reject " randNum   " => " randNum/divisor);
} while(Math.abs(randNum * factor - (long) (randNum * factor)) > ERROR);
System.out.println(randNum   " => " randNum/divisor);
  

С принтами

 729 => 303.75
285 => 118.75
84 => 35.0
123 => 51.25
999 => 416.25
75 => 31.25
reject 727 => 302.9166666666667
reject 842 => 350.83333333333337
504 => 210.0
reject 368 => 153.33333333333334
441 => 183.75
579 => 241.25
165 => 68.75
  

Это будет генерировать случайные числа до тех пор, пока у вас не будет числа, кратного 0.01.

Комментарии:

1. Как следует вызывать код? Каково решение? Я вижу только целые числа (randNum: = long) и почти целые числа (randNum * factor), дающие результат. 14600.000000000002, 38000.0, 31300.000000000004, 25500.0, 11300.0, 37900.0, ... может быть, я неправильно вызываю / инициализирую это?

2. Я предполагаю, что вы не управляете своей ошибкой округления. Если у вас есть операции, которые приводят к ошибке округления, вам нужно отформатировать их при печати.

3. То есть вы просто выдаете .0, .25, .5 и .75? Я понял запрос, что должна быть произведена каждая дробь, подобная .01, .02, … .89, .99, а не только целые кварталы.

4. Я понимаю, что число должно быть целым числом, а после деления оно должно быть кратно 0,01. Для некоторых делителей вы можете получить только определенные дроби.

5. Ну, @Joe не проясняет вопросы. Поэтому я начал понижать его голос. Мы работаем здесь часами, днями за днями, год за годом, и он уже потерял интерес?

Ответ №3:

Если вы хотите, чтобы результат «округлился» до 2 знаков после запятой (на самом деле это не округление, это просто конечное десятичное представление с двумя десятичными точками), тогда просто сгенерируйте делитель, и пусть дивиденд всегда будет равен 100, например:

  106250 / 100 = 1062.5
 116875 / 100 = 1168.75
  

Если вы хотите более интересные дивиденды, тогда разделите делитель и дивиденд. например, первым может быть любое из:

  (/1):   106250 / 100 = 1062.5
 (/2):   53125 / 50 = 1062.5
 (/10):  10625 / 10 = 1062.5
 (/4):   26562.5 / 25 = 1062.5
 (/125): 850 / 0.8 = 1062.5
  

Комментарии:

1. Поскольку в моем примере указано целое число, деленное на десятичное число, которое выдает ответ максимум с 2 десятичными знаками после запятой. Ваши образцы показывают это с делением на целое число, что неверно.

2. @Joe: вы сказали «например», имея в виду, что это один из возможных способов сделать это, а не единственный способ сделать это. должно быть понятнее.

Ответ №4:

Для меня дивиденд и делитель являются случайными числами. Я должен выдать ответ, который не требует округления десятичных знаков за пределы 2 знаков после запятой.

Если это так, ответ может быть «такого числа не существует». Вот небольшая Java-программа, которую я написал для проверки этой гипотезы:

 import java.text.DecimalFormat;

public class Test {
    public static void main(String[] args) {
        double num = Math.PI;
        DecimalFormat format = new DecimalFormat(
                "####################################0."  
                "00##############################");
        while (true) {
            for (int i = 1; i < Integer.MAX_VALUE; i  ) {
                double tmp = (i / num) * 100;
                if (tmp == (long) tmp) {
                    System.err.println("Solution - "   i   " - "   
                            format.format(tmp)   " - "   format.format(num));
                    break;
                }
            }
            pi = Math.nextAfter(num, 1);
        }
        System.err.println("No solution for "   format.format(num));
    }
}
  

Я запускал это в течение 10 минут (начиная с PI) и не нашел никаких значений, num которые не имели бы решения i . Но я заметил, что решения могут быть очень редкими. Например:

 Gotcha! - 179453441 - 5712180438.00 - 3.1415926535897714
  

Потребовалось 179 миллионов попыток, чтобы найти решение для этого делителя.