On 4/30/2013 1:13 AM, Vicente J. Botet Escriba wrote:
Le 29/04/13 20:56, Michael Marcin a écrit :
On 4/29/2013 12:18 PM, Vicente Botet wrote:
No, this is not solved by implicit/explicit conversion, but using closed arithmetic. That is
fixed<8>* fixed<8>-> fixed<8>
The C++1y proposal uses open arithmetic and
fixed<8>* fixed<8>-> fixed<16>
Using closed arithmetic the user must explicitly convert to the desired result
fixed<8> a; fixed<16> b = fixed<16>(a) * fixed<16>(a);
Whenever possible fixed-point multiply is done in a larger temporary then scaled back down. If you can't use a larger internal type it becomes much more complicated and takes many more instructions to do the operation.
I don't see how this explicit conversion of the operands helps. You've gone from needing a 32bit internal type to a 64bit internal type.
If you promote on multiply things get out of hand pretty quickly when you chain operations writing natural code.
fixed<16,16> a; auto b = a*a*a*a;
b is a 128bit fixed<64,64>
There is a middle ground solution whereby: a*a -> promoted_fixed<32,32>
so a*a*a*a would be: fixed<16,16> * fixed<16,16> -> promoted_fixed<32,32> promoted_fixed<32,32> * fixed<16,16> -> promoted_fixed<32,32> promoted_fixed<32,32> * fixed<16,16> -> promoted_fixed<32,32>
IIUC, your design is there to solve the usual case of having 2 arguments, but IMO don't works when there are multiple arguments as you can loss information here. Why do you find it is safe to do that? Why this is better and how it solves the issue?
I don't know about safe, it's not "safe" to do that on any built-in type in the language. This is basically just the difference between our use cases/requirements. I want math that can be efficient on the system. If the system had a FPU I would most likely just be using float. You need accuracy and lossless computation. I choose to use only types that can be used efficiently on the system. In this example I'm assuming a system (like many I've worked on) that has only limited 64-bit type support and no 96 or 128bit types. In this case I want to do the best I can with needed big-int style types. If I could take the lossless interface and write this code even a bit messier it'd be a non-issue. The best I can come up with is a*a*a*a into typedef fixed<16,16,int32_t> real_t; typedef fixed<16,16,int64_t> promoted_t; real_t a; auto b = real_t(promoted(promoted(a*a)*a)*a); If this works as I expect it might be enough.
Then do the scaling down only at the end. fixed<16,16> b = a*a*a*a; This would not compile on my prototype with open arithmetic and on C++1y proposal as there is a possible loss of information. An explicit downcast is needed. Unfortunately auto no longer does the intuitive thing here, but there is precedence for that in the language.
Could you give us some examples?
auto i1 = 10; // i1 is int auto i2(10); // i2 is int auto i3 {10}; // i3 is std::initializer_list<int>