Вывести целочисленные коэффициенты с плавающей запятой? - PullRequest
4 голосов
/ 20 августа 2009

У меня сложный математический вопрос, который ломает мой мозг, мою доску и все мои ручки. Я работаю с файлом, который выражает 2 значения: умножение и процент . Оба эти значения должны быть целыми числами. Эти два значения умножаются вместе для получения диапазона . Диапазон - это значение с плавающей точкой.

Мои пользователи редактируют диапазон, и мне нужно вычислить новый процент и значение мультипликатора. Смущены еще? Вот пример:

    Multiplicand: 25000 Apples
    Percentage: 400 (This works out to .4% or .004)
    Range: 100.0 Apples (Calculated by Multiplicand * Percentage)

Чтобы усложнить ситуацию, допустимые значения для процента составляют 0-100000. (Значение 0-100%) Multiplicand - это значение от 1 до 32 бит int max (предположительно без знака).

Мне нужно разрешить пользователям вводить диапазон, например так:

Range: .04 Apples

И рассчитать соответствующий процент и коэффициент. Используя первый пример:

    OriginalMultiplicand: 25000 Apples
    OriginalPercentage: 400 (This works out to .4% or .004)
    OriginalRange: 100.0 Apples (Calculated by Multiplicand * Percentage)
    NewRange: .01 Apples
    NewPercentage: 40
    NewMultiplicand: 25 Apples

Пример расчета прост, все, что требовалось, - это уменьшить мультипликатор и процентное соотношение вниз по коэффициенту масштабирования нового и старого диапазона. Проблема возникает, когда пользователь изменяет значение на что-то вроде 1400.00555. Внезапно у меня нет чистого способа отрегулировать два значения.

Мне нужен алгоритмический подход для получения значений M & P, которые дают максимально возможное значение для желаемого диапазона. Есть предложения?

Ответы [ 5 ]

1 голос
/ 20 августа 2009

Чтобы максимизировать количество сохраненных десятичных знаков, вы должны использовать P, равный 1, или 0,1%. Если это переполняет M, то увеличивается P.

Итак, для вашего примера 1400.00555, P равно 1, а M равно 1400006

Ваш алгоритм будет искать самый низкий P, чтобы M не переполнялось. И вы можете сделать бинарный поиск здесь.

public int binarySearch(int P0, int P1) {
   P = (P1 - P0)/2;
   if(P == P0) {
     if(R/(P0/100f) does not overflows 32-bit int) {
       return P0;
     } else {
       return P1;
     }
   }
   if(R/(P/100f) does not overflows 32-bit int) {
     return binarySearch(P0, P);
   } else {
     return binarSearch(P, P1);
   }
}

P = binarySearch(1, 100000);
M = round(R/(P/100f));
0 голосов
/ 20 августа 2009

Кажется, вы хотите выбрать M и P так, чтобы R = (M * P) / 100000. Так что M * P = 100000 * R, где вы должны округлить правую часть до целого числа.

Я бы умножил диапазон на 100000, а затем выбрал бы M и P в качестве факторов результата, чтобы они не выходили за допустимые диапазоны.

0 голосов
/ 20 августа 2009

скажем, у вас есть

1) M * P = A

тогда у вас есть второе значение для A, поэтому также новые значения для M и P, давайте затем вызовем M2, P2 и A2:

2) M2 * P2 = A2

Это я точно не знаю, но это то, что вы, кажется, говорите, imho: соотношение должно оставаться неизменным, тогда

3) M/P = M2/P2

Теперь у нас есть 3 уравнения и 2 неизвестных M2 и P2


Один из способов ее решения:

3) становится

M/P = M2/P2
=>M2 = (M/P)*P2

чем заменить в 2)

(M/P)*P2*P2 = A2
=> P2*P2 = A2 * (P/M)
=> P2 = sqrt(A2 * (P/M))

поэтому сначала решите P2, затем M2, если я не допустил ошибок

Должно быть некоторое округление, если M2 и P2 должны быть целыми числами.

РЕДАКТИРОВАТЬ: я забыл про целочисленный процент, так сказать

P = percentage/100000 or P*100000 = percentage
P2 = percentage2/100000 or P2*100000 = percentage2

так что просто решите для P2 и M2 и умножьте P2 на 100000

0 голосов
/ 20 августа 2009

(у меня здесь был плохой метод, но я стер его, потому что он отстой.)

EDIT:

Должен быть лучший способ, чем это. Давайте перефразируем проблему:

То, что у вас есть, является произвольным числом с плавающей точкой. Вы хотите представить это число с плавающей точкой двумя целыми числами. Целые числа, умноженные вместе и затем разделенные на 100000.0, равны числу с плавающей запятой. Единственным другим ограничением является то, что одно из целых чисел должно быть равно или меньше 100000.

Понятно, что вы не можете точно представлять числа с плавающей точкой. Фактически, вы можете ТОЛЬКО представлять числа, которые можно точно выразить в 1/100000, даже если у вас есть бесконечное число цифр точности в «умножении». Вы можете точно изобразить 333,33333: 33333333 - одно число, а 1 - другое; Вы просто не можете получить больше 3 с.

Учитывая это ограничение, я думаю, что ваша лучшая ставка заключается в следующем:

  1. Умножьте число с плавающей запятой на 100000 в целочисленном формате, возможно, длинном или некотором варианте BigNumber.
  2. Фактор это. Запишите все факторы. Не имеет значения, храните ли вы их как 2 ^ 3 или 2 * 2 * 2 или как.
  3. Соберите как можно больше факторов без умножения их всех на 100 000. Это становится вашим процентом. (Не пытайтесь делать это идеально; найти оптимальное решение - непростая задача.)
  4. Возьмите остальные факторы и умножьте их вместе. Это ваш мультипликатор.
0 голосов
/ 20 августа 2009

Как я понял из вашего примера, вы могли бы представлять range в 100000 различном multiplicand * percentage. любой выбор multiplicand даст вам удовлетворительное значение в процентах, и наоборот. Итак, у вас есть это уравнение в двух переменных:

Multiplicand * Percentage = 100.0

Вы должны вычислить другое уравнение (ограничение), чтобы получить конкретное значение Multiplicand ИЛИ Percentage для решения этого уравнения. В противном случае вы можете выбрать процент в качестве любого числа между 0-100000 и просто подставить его в первое уравнение, чтобы получить значение Multiplicand. Надеюсь, я правильно понял вопрос:)


Редактировать: ОК, тогда вы должны легко разложить диапазон. Получите range, затем попытайтесь разложить его на части, разделив диапазон на percentage(2-100000). Как только напоминание о делении станет равным нулю, вы получите факторы. Это быстрый псевдокод:

get range;
percentage = 2;
while(range % percentage != 0)
{
    percentage++;
}

multiplicand = range / percentage;

Все, что вам нужно сделать сейчас, - это рассчитать ваши лимиты:

max of percentage = 100000;
max of multiplicand = 4294967295;

Max of range = 4294967295 * 100000 = 429496729500000 (15-digit);

ваш максимальный диапазон состоит максимум из 15 цифр. double типы данных в большинстве языков программирования может представлять . Выполните расчет, используя doubles и просто конвертируйте Multiplicand & Percentage в int в конце.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...