可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have 2 convertor methods as below:
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
}
}
There are 3 important things to know:
1) The a and b variables are in the range of 0.00 to 99.99 therefore c can't have a value greater than 99.99*99.99
2) the a, b and c must not have more than 2 decimal precession e.g. a = 99.123 would be invalid.
3) you can use rounding if you'd need to as long as decimal.Round(a * b, 2) == c.
4) combinations like (1, 3), (3, 1), (2, 2), (1, 4), (0.5, 8) or even (0.25, 16) are all valid; it doesn't matter as long as c would be the product of a and b.
How would you complete the implementation of ConvertCtoAB?
Many thanks,
回答1:
Multiply C
by 10,000. Then factor this number into its prime factors. Then find a partition of the prime factors into two sets such that the product of the numbers in each set is less than 10,000. If such a partition can be found, then return these two products divided by 100 as A
and B
. Otherwise, add one to the number and try again.
For example, if C=100.07
, then the factors are 2, 2, 5, 5, 10007
. Because one of the products must include the factor 10007
, which is a prime number, the first condition can never be satisfied. So we try again with 1000701 = 3*3*3*13*2851
. This time, we can partition the number, and we have A=3.51
and B=28.51
as a possible solution.
You can do this at most 99 times. If you need 100 or more, than the input value cannot have been generated from ConvertABToC
.
This only guarantees that the result of ConvertCtoAB
, when fed back into ConvertABtoC
will produce the same C
, not the other way around. It appears to violate rule #3, but then elsewhere the question is about rounding.
If no rounding at all is allowed, then one should stop and report infeasibility after trying the original 10000*C.
回答2:
I've deleted my previous answer, as I don't believe it was helpful any more, as the question's changed so much over time.
Here's what I understand the question to be:
You are given an input (c
) of type decimal
such that:
0 <= c <= 99.99m * 99.99m
c
has at most two decimal places (i.e. c == decimal.Round(c, 2)
)
You are required to find to decimal
values a
and b
such that:
- Each of
a
and b
are in the range [0, 99.99m]
- Each of
a
and b
have at most two decimal places
decimal.Round(a * b, 2) == c
My answer is that it's still not possible for all values of c
. Counterexample: c = 9997.50
The highest possible values of a
and b
(99.99m each) gives decimal.Round(a * b, 2) == 9998.00
, so that fails with a product which is too high.
Now if you keep a
as high as it can be, and reduce b
as little as possible, we get a=99.99m, b=99.98m
- and now decimal.Round(a * b, 2) == 9997.00
, so that fails with a product which is too low.
There is no way of getting any product between those two values - we've perturbed our first attempt by as small an amount as possible. Therefore there are no values for a
and b
satisfying the problem.
(I'm anticipating a new rule being introduced to cope with this, as that seems to be the way this question is going...)
回答3:
Skeet's idea to treat the interval as itself * 100 makes everything so much clearer...
The problem is indeed without a complete solution. It asks you to create a bijective function f : A x B -> C,
where A = B = {0 ... 9999} and C = {0 ... 9999*9999 }
9999*9999 = 9998001; plus the 0, that gives a cardinality of 99,980,002.
A X B has a cardinality of 100,000,000.
A bijective function over finite sets can't be defined when the domain and codomain have different cardinalities. There will always be at most 19,998 values of c whose (a, b) breakdown will have more than one solution.
Going back on the original interval definition: the closest you can get to a proper function is something like:
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;
}
In this case, values for a between 0.02 to 99.97 will give unique results; a = 0.00 or 99.99 will be identical, likewise for a = 0.01 or 99.98. there is NO possible discrimination between these two values.
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;
}
}