atomic float add ?

Hi,

I'm desperatly trying for a week to add one float (at some place in memory) onto another float (at some other place), in an atomic way. Meaning, multiple threads should be able to add values to this memory location without interfering.
I don't wanna use mutex this they would slow down the process a lot.
I couldn't find any answer to this ! Any idea ?
(I just need to do an add, nothing else, no need for a full atomic float class if the problem is simplified this way)

Thanks !
std::atomic<float>

Check out the documentation for std::atomic.
that's precisely my problem: AFAIK, there's no such thing as "std::atomic<float>", only int types are supported, specially when it comes to add operation (unless I'm missing something ?).
http://msdn.microsoft.com/en-us/library/hh874894.aspx
Last edited on
Have you enabled C++11 support? Because it does indeed work for me. Do you get a compile time error claiming that this specialization does not exist? Does it exist for integer specializations?
There is no specialization for std::atomic<float>.
We can instantiate the std::atomic<T> generalization with T as float, but it won't have the atomic arithmetic operations. (Specializations for integral types support arithmetic operations.)

Can't you use a simulated fixed point type for the floating point value?

Something along these lines:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <atomic>
#include <iostream>
#include <cmath>

struct my_atomic_float
{
    static constexpr std::size_t digits_after_decimal = 6 ;
    static constexpr float scaling = 1000000.0 ;
    static constexpr long long scale( float f = 0 ) { return std::llround( f * scaling ) ; }
    
    std::atomic< long long > fixed_point ; 
    
    my_atomic_float( float f ) : fixed_point( scale(f) ) {}
    operator float() const { return fixed_point / scaling ; }
    my_atomic_float& operator+= ( float f ) { fixed_point += scale(f) ; return *this ;  }
    
    // etc.
};

std::ostream& operator<< ( std::ostream& stm, const my_atomic_float& f ) 
{ return stm << f.fixed_point / my_atomic_float::scaling ; }

// etc.

int main()
{
    my_atomic_float f(23.8) ;
    f += 2.3 ;
    std::cout << f << '\n' ;
}

http://coliru.stacked-crooked.com/a/6685f21a2e52a2de
But the store() and load() functions should be there; does this still compromise atomicity of the variable?
> But the store() and load() functions should be there;

Yes. As also are the exchange() and compare_exchange() family of functions.


> does this still compromise atomicity of the variable?

No, they do not.

But these are atomic load and store operations; these are not atomic arithmetic operations.
Thanks for the tip JLBorges, unfortunately approximation like theses are not an option in my application. I guess I'll have to find another way to achieve what I want to do.
float is an approximation.

What does this print out on your implementation?
std::cout << std::numeric_limits<float>::digits10 << '\n' ;

The standard 32-bit IEEE 754 floating-point type has a 24 bit fractional part (23 bits written, one implied), which may suggest that it can represent 7 digit decimals (24 * std::log10(2) is 7.22), but relative rounding errors are non-uniform and some floating-point values with 7 decimal digits do not survive conversion to 32-bit float and back: the smallest positive example is 8.589973e9, which becomes 8.589974e9 after the roundtrip. These rounding errors cannot exceed one bit in the representation, and digits10 is calculated as (24-1)*std::log10(2), which is 6.92. Rounding down results in the value 6.
- http://en.cppreference.com/w/cpp/types/numeric_limits/digits10

Sure float is an approximation, but just multiplying by 100000 won't handle cases where my float is a very large number, or a very small number - I deal with all kind of scale in my application.
> won't handle cases where my float is a very large number, or a very small number

Yes, the range is a serious problem.


> I just need to do an add, nothing else

If that is the case (the modified value is not read back till the end), you would be able to accumulate several adds into a local variable, and then do a single bulk add (with a mutex) periodically (say, at the end of an inner loop).
Topic archived. No new replies allowed.