Как преобразовать 2 ограниченные десятичные переменные в третью переменную и наоборот? - PullRequest
0 голосов
/ 02 ноября 2011

У меня есть 2 метода преобразования, как показано ниже:

private const decimal MaxValidValue = 99.99m;
public decimal ConvertABToC(decimal a, decimal b)
{
    return a * b;
}

public void ConvertCtoAB(decimal c, ref decimal a, ref decimal b)
{
    if (c > MaxValidValue*MaxValidValue)
    {
        throw new ApplicationException();
    }

    if (c <= MaxValidValue)
    {
        a = 1.00m;
        b = c;
    }
    else 
    {
        // need to introduce some logic or assumptions here
    }
}

Необходимо знать 3 важных момента:

1) Поэтому переменные a и b находятся в диапазоне от 0,00 до 99,99, поэтомуc не может иметь значения больше 99,99 * 99,99

2) a, b и c не должны иметь более 2 десятичных прецессий, например, a = 99.123 будет недействительным.

3)Вы можете использовать округление, если вам нужно до десятичного знака.Round (a * b, 2) == c.

4) допустимы такие комбинации, как (1, 3), (3, 1), (2, 2), (1, 4), (0,5, 8) или даже (0,25, 16);это не имеет значения, пока с будет произведением а и б.

Как бы вы завершили внедрение ConvertCtoAB?

Большое спасибо,

Ответы [ 3 ]

2 голосов
/ 03 ноября 2011

Умножить C на 10000. Затем разделите это число на основные факторы. Затем найдите разбиение простых множителей на два набора так, чтобы произведение чисел в каждом наборе было меньше 10 000. Если такой раздел можно найти, верните эти два продукта, разделенные на 100, как A и B. В противном случае добавьте один к номеру и повторите попытку.

Например, если C=100.07, то факторы равны 2, 2, 5, 5, 10007. Поскольку один из продуктов должен включать коэффициент 10007, представляющий собой простое число, первое условие никогда не может быть выполнено. Итак, мы попробуем еще раз с 1000701 = 3*3*3*13*2851. На этот раз мы можем разделить число, и у нас есть A=3.51 и B=28.51 в качестве возможного решения.

Вы можете сделать это максимум 99 раз. Если вам нужно 100 или больше, тогда входное значение не может быть сгенерировано из ConvertABToC.

Это только гарантирует, что результат ConvertCtoAB при обратной передаче в ConvertABtoC даст тот же C, а не наоборот. Похоже, что это нарушает правило № 3, но в остальном вопрос касается округления.

Если округление вообще не допускается, тогда следует остановиться и сообщить о невозможности после попытки использовать исходные 10000 * C.

1 голос
/ 03 ноября 2011

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

Вот что я понимаю вопрос будет:

Вам дан ввод (c) типа decimal такой, что:

  • 0 <= c <= 99.99m * 99.99m
  • c имеет не более двух десятичных знаков (т. Е. c == decimal.Round(c, 2))

Вам необходимо найти decimal значений a и b таких, что:

  • Каждый из a и b находится в диапазоне [0, 99.99m]
  • Каждый из a и b имеет не более двух десятичных знаков
  • decimal.Round(a * b, 2) == c

Мой ответ таков: все еще невозможно для всех значений c. Контрпример: c = 9997.50

Максимально возможные значения a и b (по 99,99 м каждый) дают decimal.Round(a * b, 2) == 9998.00, поэтому происходит сбой при слишком высоком продукте.

Теперь, если вы сохраните a как можно выше и уменьшите b как можно меньше, мы получим a=99.99m, b=99.98m - и теперь decimal.Round(a * b, 2) == 9997.00, так что произойдет сбой с слишком низким продуктом.

Невозможно получить какой-либо продукт между этими двумя значениями - мы смутили нашу первую попытку настолько малым количеством, насколько это возможно. Поэтому нет никаких значений для a и b, удовлетворяющих проблеме.

(Я ожидаю, что будет введено новое правило, чтобы справиться с этим, так как кажется, что этот вопрос идет ...)

0 голосов
/ 02 ноября 2011

Идея Скита рассматривать интервал как саму себя * 100 делает все намного яснее ...

Проблема действительно не имеет полного решения. Он просит вас создать биективную функцию f: A x B -> C,
где A = B = {0 ... 9999} и C = {0 ... 9999 * 9999}

9999 * 9999 = 9998001; плюс 0, что дает мощность 99 980 002

A X B имеет мощность 100 000 000.

Биективная функция над конечными множествами не может быть определена, когда домен и кодомен имеют разные мощности. Всегда будет не более 19 998 значений c, разбивка (a, b) которых будет иметь более одного решения.

Возвращаясь к исходному определению интервала: самое близкое к правильной функции что-то вроде:

public decimal Ab2C(decimal a, decimal b)
{
    if(a != 99.99 and a != 99.98)
        return a*100 + b;
    return (100-a)*100 + b; // for instance;
}

В этом случае значения от 0,02 до 99,97 дадут уникальные результаты; а = 0,00 или 99,99 будет идентичным, аналогично для а = 0,01 или 99,98. между этими двумя значениями НЕТ возможной дискриминации.

public void C2AB(decimal c, out decimal a, out decimal b)
{
    // todo: sanity checks.
    if (c <= 99.99)  // either a = 0.00, or a = 99.99; and b = c.
    {
        b = c;
        a = 0.00;
        return;
    }

    if (c <= 2*99.99)
    {
        b = c - 99.99;
        a = 0.01; // or 9.98.
        return;
    }
    a = c / 100;
    b = c % 100;
}

}

...