Post by Rick C. HodginPost by Scott HemphillPost by Rick C. HodginI don't see (2,3,4) as being easy. v1=2, v2=3, v3=4, total
of 9, rounding up to 16, means 7 can be added. How do you
distribute 7 amongst the 2,3,4 proportionally?
I view it as being easy, since rounding each of (3.55,5.33,7.11) to the
nearest integer produces a sum of 16, which is what was desired.
Let's consider the possible range of values (we'll call them a,
b, and c instead of v1, v2, and v3).
If we consider a, b, c, all in the range from 1..32, we have a
4096 match exactly at the 8-bit boundary, and 28,672 need some
adjustment because their (a + b + c) % 8 does not equal 0.
If we apply projected increases and round, we find that of those
28,672 only 19,895 fall on an exact boundary using the project-
and-round logic, leaving 8,777 need post-project-and-round ad-
justment.
Here's the pseudo-code (written in Visual FoxPro, "ln" prefixes
lnMatch = 0 && Number that match exactly
lnMismatchType1 = 0 && Number that project exactly
lnMismatchType2 = 0 && Number that miss the projection
FOR lnA = 1 TO 32 && a = 1..32
FOR lnB = 1 TO 32 && b = 1..32
FOR lnC = 1 TO 32 && c = 1..32
* See where we are
lnABC = (lnA + lnB + lnC)
lnTarget = lnABC + IIF(lnABC % 8 = 0, 0, 8 - (lnABC % 8))
lnDiff = lnTarget - lnABC
* Are we there?
IF lnDiff = 0
* Yes, it's on a boundary of 8
lnMatch = lnMatch + 1
ELSE
* Need to adjust up to next highest boundary of 8
lnAStep = lnA / lnABC
lnBStep = lnB / lnABC
lnCStep = lnC / lnABC
lnA2 = lnA + ROUND(lnDiff * lnAStep, 0) && Round to
lnB2 = lnB + ROUND(lnDiff * lnBStep, 0) && nearest
lnC2 = lnC + ROUND(lnDiff * lnCStep, 0) && whole number
* Compute our new total
lnABC2 = lnA2 + lnB2 + lnC2
lnDiff2 = lnTarget - lnABC2
IF lnDiff2 = 0
lnMismatchType1 = lnMismatchType1 + 1
ELSE
lnMismatchType2 = lnMismatchType2 + 1
ENDIF
ENDIF
NEXT
NEXT
NEXT
* Display the totals
? lnMatch, lnMismatchType1, lnMismatchType2
If I missed something, I'm open to correcting it.
That looks right. First, a side comment. You're making the arithmetic
slightly more complicated than it needs to be. You don't have to
calculate the difference between the target and the total and the value
of the individual steps. You can simply calculate:
lnA2 = ROUND(lnA * lnTarget/lnABC),
etc.
Now let's see what we can learn about the 8777 hard triples. If you
look at the number you (and I) are rounding, it consists of an integer
part and a fractional part. So I will call the fractional parts fA, fB,
and fC. Each fraction lies on the interval [0,1), i.e. it can be zero,
but it can't be one. Also, the total of fA, fB, and FC is an integer,
so it has to be either zero, one, or two. It can only be zero if all
three fractions are zero, so this already rounds exactly, and can't be a
hard triple. If two of the fractions are zero, then the third fraction
must also be zero in order for their sum to be an integer, so we can
never have just two fractions which are zero. If there is just one
fraction that is zero, then the sum of two other fractions must be one.
We can reorder the fractions if necessary and we have:
fA = 0
0 < fB < 1/2
1/2 < fC < 1
fB and fC can't be exactly one-half, since they were arrived at by
dividing a number which is a multiple of 8 by a number which is not a
multiple of 8. There are more factors of two in the numerator than in
the denominator, so after cancellation, there can't be any twos in the
denominator. The sum of fB and fC is more than 1/2 and less than 3/2,
so it has to be one. After rounding fB down to zero and rounding fC up
to one, the total is still one. Therefore, rounding produces the
correct total, and this is not one of our hard triples
In summary, none of our hard triples involve rounding a number which has a
fractional part of zero.
So we have the following cases left:
1) All three fractions are less than one-half
2) Two fractions are less than one-half, one is more than one-half
3) Two fractions are more than one-half, one is less than one-half
4) All three fractions are more than one-half
Case 1)
If all three fractions are less than one-half, then their sum lies
between zero and 3/2. Therefore their sum must be one, but they all
round down to zero. This is one of our hard triples.
Case 4)
If all three fractions are more than one-half, then their sum lies
between 3/2 and three, so it must be two. The fractions all round up to
one, totalling three instead of two. This is one of our hard triples.
Case 2)
The sum of the three fractions must lie between one-half and two, so it
must be one. After two fractions are rounded down to zero, and one
rounded up to one, the sum is still one. This is not a hard triple.
Case 3)
The sum of the three fractions must lie between one and 5/2, so it must
be two. After two fractions are rounded up to one, and one rounded down
to zero, the sum is still two. This is not a hard triple.
So there you have it. You will have to decide what to do with three
fractions that all lie between 0 and one-half, or three fractions that
all lie between one-half and one.
For example, fA=0.3, fB=0.3, fC=0.4. Their total is one. Do you
promote fC to one because it's the biggest of the fractions? What if
lnA is a lot bigger than lnB or lnC? It might be that rounding fA to
one might be a smaller proportional error than rounding fC to one.
Similarly with, fA=0.6, fB=0.7, fC=0.7. Their total is two, but you
can't round them all up, because their total would then be three. So
which one do you demote: fA? Does it depend on the relative size of
lnA, lnB, and lnC? Here's another consideration: suppose lnB and lnC
have the same value. Do you want to preserve that equality even though
it might mean a greater relative error by demoting fA?
Scott
--
Scott Hemphill ***@alumni.caltech.edu
"This isn't flying. This is falling, with style." -- Buzz Lightyear