Is there a way to find the average of two floats while rounding to whole number?

It is not necessary to round to the nearest whole value, but I need something that allows me to take the average of two floats and comes up with a whole value that is about halfway between them. Like this:

1.f,9.f = 5.f
2.f,9.f = 5.f or 6.f

Currently I am using floor( (a+b)*0.5 ).
I've also considered casting to int then back to float, but this seems costly.

I wish to find an alternative means that does not rely on microsoft libraries and is faster than casting twice.

Thanks.
Last edited on
Currently I am using floor( (a+b)*0.5 ).
I've also considered casting to int then back to float, but this seems costly.
They're both expensive. This is only relevant if you're doing the operation billions of times. If that's the case, perhaps you should consider moving away from float.
If you have to do it billions of times, you offload the averaging to our desktop supercomputer vector processor we call a graphics card.

And the cast from float to int is actually very fast if you can use certain compiler optimizations and/or SSE.
you can get rid of unsightly fractions with isolation and subtraction. subract 1 until you get a negative. add 1 to get the lowest positive. subtract the lowest positive from the float you were too cheap to cast:
3.14 - 1
2.14 - 1.0
1.14 - 1.0
0.14 - 1.0
-0.86 less than zero!

-0.86 + 1.0
0.14

3.14 - 0.14 = 3.0

time the different methods and see what is faster. my method could be twice as fast as casting and three times as fast as floor()!
What if the number is 1.54E+9?
Last edited on
exactly! what if. 1.54E+9 wasn't in his example range, but we will never know which of the three mentioned methods performs better without a test. i don't see why my method wouldn't produce a correct result.

while i have your ear, can you be a little more specific than "moving away from float"? we can add those to the list of things to test and ponder.
Instead of using floating point arithmetic, to use fixed point arithmetic. There are many ways to do this, and all of them use integers. The most obvious one is to treat the least significant decimal digit of the integer as 1/100th of a unit (1->.01, 50->.5, 100->1, etc.). A better method is to treat a unit as 1/256th of a unit (1->.00390625, 0x80->.5, 0x100->1). This makes truncating the value, a single shift operation: x>>8. Leaving only the fractional part is also very simple: x&0xFF.
For added precision, the two least significant bytes can be used as the fractional part, at the cost of having a lower upper range.
does fixed point pass the helios test: what if the number is 1.54E+9?

i'm no good at math. given that one or two bytes are devoted to the fractional unit, is 1.54E+9 under the upper limit? this site lists a possible upper limit of 2147483647 (2.147483647E+9), but that is with all the bits.


i tried my method! it gets unbearably slow at E+08 and above. i will say it fails the helios test. otherwise, it works.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
float wholefloat(float fnumber) {
	float fchange;
	// make copy to mess with
	fchange = fnumber;

	// we will only work with positive numbers
	// make it positive for now, negative after loop
	if(fnumber < 0) fchange *= -1.0;

	// decrement by one until we get something less than one
	while(fchange > 1.0) {
		fchange -= 1.0;
	}

	// if orginal was negative make changed result negative
	if(fnumber < 0) fchange *= -1.0;

	// subtract the fractional part (less than one)
	return(fnumber - fchange);
}
Using a 32-bit signed integers and
8 bits for fractions: [-8,388,608 (2^31/2^8);+8,388,607.99609375 ((2^31-1)/2^8)]
16 bits for fractions: [-32,768 (2^31/2^16);+32,767.9999847412109375 ((2^31-1)/2^16)]

Why would you use that method when you can just shift the decimals away? Actually, why would you ever use that method?

And I was wrong in my previous post. If you just do x&0xFF, you'll get wrong results if x<0 due to two's complement. For example, 0xFFFFFFFF is the closest negative value to zero. If you just AND it with 0xFF, you'll get -255/256, which is wrong. It should give -1/256. The correct formula for negatives is (-x)&0xFF.
ahh! fixed point fails the helios test. huh. the upper limit of fixed point is a bit lower than the horrible performance upper limit using my method.

when would i use my method rather than learn and write fixed point code and replace all my math calls with calls to the fixed point routines? and maybe there could be output problems. i am guessing fixed point numbers would have to be converted for display and debugging.

man, now that i think about it, i'd have to be hurting pretty bad to change an existing program over to fixed point so i could shift a decimal away. but i'm lazy like that. i'm sure AlwaysLearning has his floating point routines fully functional by now.
Can somebody tell me why floor() is so slow, and why a home-brewed solution could be made faster?
If a faster, general-purpose solution existed, would not the implementation of floor() use it?
ahh! fixed point fails the helios test.
No, it doesn't. I chose that large number to show you that your method takes longer and longer as the number gets bigger. floor() and fixed point arithmetic takes always the same time regardless of the value.

when would i use my method rather than learn and write fixed point code and replace all my math calls with calls to the fixed point routines?
Like I said earlier, fixed point arithmetic is only worthwhile if you need to do things really, really, really fast. For example, I once used it when I needed to perform around three million operations with decimals in less than 50 milliseconds.
Otherwise, just use floats with their C functions.
No, it doesn't. I chose that large number to show you that your method takes longer and longer as the number gets bigger. floor() and fixed point arithmetic takes always the same time regardless of the value.

regular fixed point doesn't count as high as the helios number, so fixed point fails the helios test.

you don't appear to understand the helios test. the helios number tests for an extreme and unlikely possibility, which is helpful in this case when we need fast float-to-integer conversions of values as high as 1.54E+9.

the helios test is incredibly general-purpose and works equally as well in pretty much any everyday situation with a number. for example, if PanGalactic says he can quickly eat cheeseburgers, we can apply the helios test:
What if the number is 1.54E+9?

whether PanGalactic can or can't put away 1.54E+9 cheeseburgers is of great importance in some situations. at the moment, I can't think of one situation. or 1.54E+9 situtations.
^You miss the point. The point is that you should use a general purpose algorithm that works well in ALL situations rather then one that works for only some situations. And besides, the topic title says "Is there a way to find the average of two floats while rounding to whole number?", not "Is there a way to find the average of two small floats..."
^You miss the point. The point is that you should use a general purpose algorithm that works well in ALL situations rather then one that works for only some situations. And besides, the topic title says "Is there a way to find the average of two floats while rounding to whole number?", not "Is there a way to find the average of two small floats..."

AlwaysLearning's examples don't go above 12, though you may be right about implying the entire range of a float through the use of floats. in that case of ALL, fixed point is a bad suggestion.

on the other hand, i suppose it is better to have solutions with a variety of benefits and limitations for those odd times when you don't need the entire range or precision of a given variable type, like fixed point.

the average of two floats! oh man. there is another limit. the two floats shouldn't add up to more than a float can handle. does C/C++ still have overflow errors? i don't even know how to check for that. i've never had that problem. i guess i've never had ALL the problems or attempted to fit ALL the situations.

floor() may actually be unsuitable for two floats that are larger than half their limit! wait, don't the math functions work with double? is that an extra cast requiring more time? float to double then back to float?
The upper limit for a 32-bit float is 3.40282e+038. Half of that is 1.70141e+038. If you're getting numbers so large, it's either an error or the programmer being stupid and using the wrong type.
Topic archived. No new replies allowed.