3

Consider a java project doing lots of floating point operations where efficiency and memory consumption can be important factors - such as a game. If this project targets multiple platforms, typically Android and the desktop, or more generally 32 and 64 bit machines, you might want to be able to build a single and a double precision build of your software.

In C/C++ and other lower level languages, this is easily achieved by typedef statements. You can have:

typedef float myfloat;

and the day you want to go 64 bit just change that to:

typedef double myfloat;

provided you use myfloat throughout your code.

How would one achieve a similar effect in java?

A global search and replace of "float" by "double" (or vice-versa) has the huge drawback of breaking compatibility with exterior libraries that only offer one flavor of floating point precision, chief among them certain functions of the java.lang.Math class.

Having a high-level polymorphic approach is less than ideal when you wish to remain efficient and keep memory tight (by having lots of primitive type arrays, for instance).

Have you ever dealt with such a situation and if so, what is in your opinion the most elegant approach to this problem?

schmop
  • 1,440
  • 1
  • 12
  • 21
  • Looks like there's no typedef in java, see here: http://stackoverflow.com/questions/1195206/is-there-a-java-equivalent-or-methodology-for-the-typedef-keyword-in-c This is one of the many features of C that I wish Java had. – McLovin May 06 '14 at 16:47
  • I just use `double` every where. It is pretty rare that you really want to use a float, in which case, you don't want it switch-able. – Peter Lawrey May 06 '14 at 16:54
  • @PeterLawrey I assure you that if you are writing code that you want to execute on a five year old phone AND the latest PC gaming rig, you really would like to be able to target both – schmop May 06 '14 at 16:56
  • 1
    What exactly would be the point of doing this? The sizes of `float` and `double` are fixed in Java, regardless of the target operating system or its underlying architecture. – NullUserException May 06 '14 at 16:58
  • @schmop if you are targeting a five year old phone you have lots more issues to worry about than whether you use `float` or `double`, like does it even run Java 1.4 or is it much older, or not at all. Perhaps floating point is not a good idea of such an under resourced device. – Peter Lawrey May 06 '14 at 17:01
  • @NullUserException I don't understand your point. double operations are twice as slow as float operations in a 32 bit architecture and take up twice as much space. There are clearly situations where this matters. – schmop May 06 '14 at 17:05
  • @schmop If you are worried about 4-bytes, you are going to get a shock when you realise an empty HashMap uses over 80 bytes, and an empty String uses 40 bytes. – Peter Lawrey May 06 '14 at 17:07
  • I had a look at 5 years old phones, and I don't think any developed country would still use them http://www.cnet.com/pictures/top-10-most-popular-cell-phones-of-2009-photos/ – Peter Lawrey May 06 '14 at 17:08
  • @PeterLawrey You don't seem to be aware that programs can store more than one number :) An array of 100000 floats or doubles is not a 4 byte difference! – schmop May 06 '14 at 17:18
  • @schmop Unless you are talking old phones again, 400KB still isn't very much. A JVM can use over 100 MB of memory just starting. 400 KB of memory in a PC with worth about 0.05 cents. Let say you have one billion floats, you start having an argument, but how many applications use this many floats. (BTW 4 GB of memory is worth about one hour of your time on minimum wage.) Is this what you have in mind for your library? – Peter Lawrey May 06 '14 at 17:21
  • 2
    @PeterLawrey Look, clearly you are not familiar with the style of programming I am talking about. 400KB of GPU bandwidth 60 times per second can be a huge difference. May I suggest you ignore this question instead of repeatedly trying to convince that this is a non-issue? – schmop May 06 '14 at 17:26
  • @schmop So this is strictly a performance concern? – NullUserException May 06 '14 at 17:30
  • 1
    @schmop You seem to be very keen to find a solution which no concrete problem to solve. You know very well that no GPU will run Java. This is a non-issue with a non-solution to a non-problem, so I suggest you give it up. – Peter Lawrey May 06 '14 at 17:31
  • @PeterLawrey Yes, my wording of that comment was plain wrong. Still, I've seen programs jump from 60 to 30 fps by a change in precision. And regarding size, I'm not interested in any specific program whether it uses 4B, 400KB or 400MB. There is a difference between double and float that is exactly 2 to 1 and you can want a same piece of code to run on old phones or your client's 15 year old computer or whatever. I will not argue the validity of the question further. Even if it were wholly invalid, I'm still interested in seeing the solutions that people put forward. – schmop May 06 '14 at 17:38
  • 2
    @PeterLawrey [My current phone](http://www.lg.com/us/cell-phones/lg-VN270-cosmos-touch) takes offense at your dig against old phones! (Though I wouldn't expect to play games on it at anything faster than 30 seconds per frame). – yshavit May 06 '14 at 17:42
  • @schmop you have a point, but I feel in specific cases, with specific problems, you can work around this. I have written data processing libraries to handle 16-bit fixed point, but I was struggling to get the data into 256 GB of memory. – Peter Lawrey May 06 '14 at 17:53

4 Answers4

5

The official Android documentation says this about float vs. double performance:

In speed terms, there's no difference between float and double on the more modern hardware. Space-wise, double is 2x larger. As with desktop machines, assuming space isn't an issue, you should prefer double to float.

So you shouldn't have to worry about performance too much. Just use the type that is reasonable for solving your problem.

Apart from that, if you really want to have the ability to switch between double and float, you could wrap your floatin point value in a class an work with that. But I would expect such a solution to be slower that using any floating point primitive directly. As Java does not support overloading operators, it would also make your math code much more complicated. Think of something like

double d = (a+b)/c;

when using primitives versus

MyFloat d = a.add(b).div(c);

when working with wrapper objects. According to my experience, the polymorphic approach makes maintaining your code much harder.

Marc Hauptmann
  • 688
  • 5
  • 18
2

I will omit the part saying that for example double should be just fine etc. Others covered that more than good. I'm just assuming you want to do it - no matter what. Even for the sake of experiment to see what's the performance/memory difference - it's interesting.

So, a preprocessor would be great here. Java doesn't provide one.

But, you can use your own. Here are some existing implementations. Using javapp for example, you will have #define.

Community
  • 1
  • 1
Adam Stelmaszczyk
  • 19,665
  • 4
  • 70
  • 110
1

This is not practical without great pains.

While you could define your high level API's to work with wrapper types (e.g. use Number instead of a specific type and have multiple implementations of the API that uses Float or Double under the hood), chances are that the wrappers will eat more performance than you can ever gain by selecting a less precise type.

You could define high level objects as interfaces (e.g. Polygon etc.) and hide their actual data representation in the implementation. That means you will have to maintain two implementations, one using float and one for double. It probably requires considerable code duplication.

Personally, I think you are attempting to solve a non-existant conundrum. Either you need double precision, then float isn't an option, or float is "good enough", then there is no advantage of ever using double.

Simply use the smallest type that fits the requirements. Especially for a game float/double should make little difference. Its unlikely you spend that much time in math (in java code) - most likely your graphics will determine how fast you can go.

Generally use float and only switch to double for parts where you need the precision and the question disappears.

Durandal
  • 19,919
  • 4
  • 36
  • 70
0

Java does not have such a functionality, aside from brute-force find-and-replace. However, you can create a helper class. Shown below, the type you will change to change the float precision is called F:

public class VarFloat {
    F boxedVal;
    public VarFloat(F f){
        this.boxedVal = f;
    }
    public F getVal() { return boxedVal; }
    public double getDoubleVal() { return (double)boxedVal; }
    public double getFloatVal() { return (float)boxedVal; }
}

Where at all possible, you should use getVal as opposed to any of the type-specific ones. You can also consider adding methods like add, addLocal, etc. For example, the two add methods would be:

public VarFloat add(VarFloat vf){ return new VarFloat(this.boxedVal + vf.boxedVal); }

public VarFloat addLocal(VarFloat vf){ this.boxedVal += vf.boxedVal; return this; // for method chaining }

nanofarad
  • 40,330
  • 4
  • 86
  • 117