#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 миллионов попыток, чтобы найти решение для этого делителя.