0

Some days ago I downloaded sources of SumatraPDF and started exploring it. I found that library MuPDF сontains on interesting function, but not understand it.

static inline int fz_mul255(int a, int b) {
    int x = a * b + 128;
    x += x >> 8;
    return x >> 8;
}

In some other sources I found another definition of mul255 function:

(a+1)*b >> 8

What is it? Help.

njuffa
  • 23,970
  • 4
  • 78
  • 130
nulpatrol
  • 28
  • 4
  • 2
    This looks like a rounded multiplication of fixed-point data with 8 fractional bits, where each fixed-point number is stored in an `int`. However, in initial thought, the two variants do not seem to be equivalent, and either code deviates from what I would expect such a function to look like: `(a * b + 128) >> 8`. Is there any auxiliary information in the code (comments?) pertaining to the function or the data type? – njuffa Jul 03 '14 at 21:32
  • Your first snippet could represent a rounded fixed-point multiplication with eight fractional bits, followed by scaling by 257/256, which is the approximate reciprocal of 255/256. The purpose of this scaling isn't clear without having more context. – njuffa Jul 03 '14 at 21:52
  • 1
    @Glutton: I am not at all sure whether what I wrote in my comment is the answer. There is presumably a reason that this function is called `mul255`, but it is not clear to me. I tried to further reverse engineer in my second comment above, trying to somehow work in the `255`. What is also confusing is that there are two conflicting definitions of this function. So without further corroboration by the original poster I am afraid I am speculating, not answering. – njuffa Jul 03 '14 at 21:56

2 Answers2

1

In graphics we often use scaled integer values (range 0 to 255) to represent color values in the range of 0.0 to 1.0.

The mul255 function multiplies two such scaled integers, such that 255 * 255 = 255.

The implementation in MuPDF is based on Jim Blinn's accurate scaling method from the book "Dirty Pixels" by Jim Blinn. The other implementation you quoted (a+1)*b >> 8 is a faster, but less accurate, approximation.

ccxvii
  • 1,873
  • 1
  • 13
  • 11
0

If it weren't for the second line (x += x >> 8) I'd know exactly what the method does. If we remove it, for purpose of discussion:

static inline int fz_mul255(int a, int b) {
    int x = a * b + 128;
    // x += x >> 8;
    return x >> 8;
}

The method now multiples a * b, which are fixed-point numbers with 8 fractional bits, rounding to the nearest result. Specifically, the a * b is the multiple, the + 128 rounds to the nearest (remember that this gets shifted out, so it only has an effect if it causes a carry to the next most significant bit position after bit 7), and the >> 8 corrects the position of the point (because multiplying two fixed-point values with 8 fractional bits using integer arithmetic yields a fixed-point value with 16 fractional bits).

The only question then is what that 'x += x >> 8' is for, and that I'm afraid I do now know. In effect it multiplies the result by (1 + 1/256).

davmac
  • 20,150
  • 1
  • 40
  • 68
  • The arguments are not fixed-point numbers with 8 fractional bits; they are scaled integers (255 represents 1.0). – ccxvii Jul 10 '14 at 13:37
  • "The arguments are not fixed-point numbers with 8 fractional bits" - they _are_ in the context of my answer, but I see what you mean, and this would explain the scaling step in the method which I have explicitly commented out. – davmac Jul 10 '14 at 14:15