Just for grins, I tried getting rid of the If statement. I ended up with this monstrosity, but when I tested it, DigiRev's solution was in the vicinity of 33 times as fast as this. Frankly, I'm not surprised.
Total += (((rating - 1) * 5) + ((CInt(2 ^ rating) >> 1) And 1))
With linear mapping:
If Avg(rating) = 1 then Score = 1 : x1 = 1, y1 = 1
If Avg(rating) = 3 then Score = 10: x2 = 3, y2 = 10
You can have an equation:
Score = a*Avg(rating) + b, where a = 4.5 and b = -3.5 :
y = a*x + b
a = (y2-y1)/(x2-x1),
b = y1-a*x1
or:
Score = 4.5*Avg(rating) - 3.5
From that,
If Avg(rating) = 1 then Score = (4.5)*1 - 3.5 = 1
If Avg(rating) = 1.5 then Score = (4.5)*(1.5) - 3.5 = 3.25
If Avg(rating) = 2 then Score = (4.5)*2 - 3.5 = 5.5
If Avg(rating) = 2.5 then Score = (4.5)*(2.5) - 3.5 = 7.75
If Avg(rating) = 3 then Score = (4.5)*3 - 3.5 = 10
Last edited by anhn; May 9th, 2008 at 06:07 PM.
Don't forget to use [CODE]your code here[/CODE] when posting code
If your question was answered please use Thread Tools to mark your thread [RESOLVED]
I was a bit surprised to find that the code posted by Jemidiah is about 30% faster than a simplified version of the If statement approach DigiRev originally posted. In theory, the integer add should be very fast, though all the branches will be potentially costly. However, in VB.NET, integer adds are implemented in a fashion that makes them fairly slow compared to what should be possible, so the advantages of the simple math are non-existent and the cost of the branches are much greater than the additional math required in jemidiah's code.
A bit OT, but the original question seems to have been answered, and this is a programming forum after all:
I can understand why the if branches would be slower, but why did they implement integer addition in a way that makes it about as slow as multiplications? That seems really silly.
The time you enjoy wasting is not wasted time. Bertrand Russell
Thanks a bunch. Sorry it took so long to reply (had to go get a root canal ). I like the:
Score = 4.5 * AvgRating - 3.5
And it seems to work great. This is for PHP code so I'm not sure how fast it is (the example I gave was like VB syntax). Speed isn't so much of an issue but I'm sure that is still faster.
I'm not sure how you came up with that 4.5 * AvgRating - 3.5 (my math skills are that bad).
A bit OT, but the original question seems to have been answered, and this is a programming forum after all:
I can understand why the if branches would be slower, but why did they implement integer addition in a way that makes it about as slow as multiplications? That seems really silly.
The bit about integer addition annoyed the heck out of me when I first discovered it. I had an approximation for the Pythagorean Theorem based on the RISC subset of the instruction set for x86 processors, and decided to test it in VB. It turned out that using the full method, complete with multiplications and square roots, was faster than the integer and bit shifting method. That kind of kills off some optimization options.
By the way, in this case, turning off the integer overflow checks improved the performance of both routines by about 30%, as well, but the benefit was roughly equal for both techniques (actually, I think it helped the branching technique by about 40%, and the mathematical approach by just under 30%).
I'm not sure how you came up with that 4.5 * AvgRating - 3.5 (my math skills are that bad).
In case you may need if you have different scale in the future: How it comes up with 4.5 and -3.5 is explained in post#4 in term of linear equation solving.
Don't be supprise, I used to be a maths teacher for more than 10 years three decades ago.
I did use this method many times when I want to standardize the marks I gave to my students as sometimes a test was too hard and the top student get only 12/20 and I wanted to move that mark up to 18/20; and the lowest mark 3/20 is also moved up to 6/20.
Scale [3 - 12] become Scale [6 - 18].
Don't forget to use [CODE]your code here[/CODE] when posting code
If your question was answered please use Thread Tools to mark your thread [RESOLVED]
In this case, the formula comes about like this:
You have numbers from 1-3, you want to map them to numbers from 1-10. (1) First shift the numbers from 1-3 to the range 0-2. (2) Now multiply that range from 0-2 by 4.5 to get a range from 0-9. (3) Now shift the range from 0-9 to 1-10.
Algebraically this becomes
(1) A = (AvgRating - 1); A is in the range 1-3 minus 1 = 0-2
(2) B = A*4.5; B is in the range 0-2 times 4.5 = 0-9;
(3) C = B + 1 = Your Answer; C is in the range 0-9 plus 1 = 1-10.
Combine 1, 2, and 3 by substitution to get
C = B + 1 = A*4.5 + 1 = (AvgRating - 1)*4.5 + 1 = AvgRating*4.5 - 4.5 + 1 = AvgRating*4.5 - 3.5 = your answer.
Alternatively, you can think of it as getting the 1 AvgValue to map to 1, and getting the 3 AvgValue to map to 10, using a "linear" map. That is,
f(1) = 1,
f(3) = 10,
f(AvgRating) is linear.
You might remember linear functions from an algebra course. In this context, we know that f must be of a certain form:
f = a*AvgRating+b
where a and b are some constants. If you graph f, you'll see that it ascends or descends smoothly, like your 1-10 rating scale should, which is why we use a linear function here instead of something crazy.
With the above, finding a and b is all algebra:
f(1) = a*1+b = a + b = 1 -> a = 1-b
f(3) = a*3+b = 3a + b = 3(1-b)+b = 3-2b = 10 -> 2b = -7 -> b = -7/2 = -3.5 -> a = 1-(-3.5) = 4.5, so we have
f(AvgRating) = 4.5*AvgRating - 3.5 = your answer.
Anhn and Logophobic used generalizations of this technique which allow the easy scaling from one coordinate system (one linear range) to another. For instance, you can create the Celsius to Fahrenheit conversion formula from this:
We're converting from system R1 where we have a low and high end to the scale, as well as a value, to the system R2. Let's convert from Fahrenheit to Celsius, so using limits we know the conversions for,
Value1 will then of course be in [answer this yourself first if you wish to truly follow along] the scale that begins with the letter F, and Value2 will be in Celsius. Let's make this more obvious by using these names:
Value1 = F,
Value2 = C.
Then the conversion formula falls out to be
C = (F-32)*(100-0)/(212-32) = (F-32)*100/180 = (F-32)*5/9, which might be a familiar formula to you.
You can check this formula, among other ways, by checking what F = -40 gives. Perhaps you'll recall that F and C scales are actually equivalent at -40 degrees, so C should be -40 here:
Yay, it works. This same method was used in your case to provide your magical formula, and can be proven using the second explanation from above, or even (if you're a bit more creative) the first explanation.
I hope this helped make the math seem a bit less mystical
The time you enjoy wasting is not wasted time. Bertrand Russell