pub struct AtomicF32 { /* private fields */ }Expand description
Atomic 32-bit floating point number.
Provides easy-to-use atomic operations with automatic memory ordering
selection. Implemented using AtomicU32 with bit conversion.
§Memory Ordering Strategy
This type uses the same memory ordering strategy as atomic integers:
-
Read operations (
load): UseAcquireordering to ensure visibility of prior writes from other threads. -
Write operations (
store): UseReleaseordering to ensure visibility of prior writes to other threads. -
Read-Modify-Write operations (
swap,compare_set): UseAcqRelordering for full synchronization. -
CAS-based arithmetic (
fetch_add,fetch_sub, etc.): UseAcqRelon success andAcquireon failure within the CAS loop. The loop ensures eventual consistency.
§Implementation Details
Since hardware doesn’t provide native atomic floating-point operations,
this type is implemented using AtomicU32 with f32::to_bits() and
f32::from_bits() conversions. This preserves bit patterns exactly,
including special values like NaN and infinity.
§Features
- Automatic memory ordering selection
- Arithmetic operations via CAS loops
- Zero-cost abstraction with inline methods
- Access to underlying type via
inner()for advanced use cases
§Limitations
- Arithmetic operations use CAS loops (slower than integer operations)
- CAS comparisons use exact IEEE-754 bit patterns, so different NaN
payloads and
0.0/-0.0are treated as different values - No max/min operations (complex floating point semantics)
§Example
use qubit_atomic::Atomic;
use std::sync::Arc;
use std::thread;
let sum = Arc::new(Atomic::<f32>::new(0.0));
let mut handles = vec![];
for _ in 0..10 {
let sum = sum.clone();
let handle = thread::spawn(move || {
for _ in 0..100 {
sum.fetch_add(0.1);
}
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
// Note: Due to floating point precision, result may not be exactly 100.0
let result = sum.load();
assert!((result - 100.0).abs() < 0.01);Implementations§
Source§impl AtomicF32
impl AtomicF32
Sourcepub fn load(&self) -> f32
pub fn load(&self) -> f32
Gets the current value.
§Memory Ordering
Uses Acquire ordering on the underlying AtomicU32. This ensures
that all writes from other threads that happened before a Release
store are visible after this load.
§Returns
The current value.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<f32>::new(3.14);
assert_eq!(atomic.load(), 3.14);Sourcepub fn store(&self, value: f32)
pub fn store(&self, value: f32)
Sets a new value.
§Memory Ordering
Uses Release ordering on the underlying AtomicU32. This ensures
that all prior writes in this thread are visible to other threads
that perform an Acquire load.
§Parameters
value- The new value to set.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<f32>::new(0.0);
atomic.store(3.14);
assert_eq!(atomic.load(), 3.14);Sourcepub fn swap(&self, value: f32) -> f32
pub fn swap(&self, value: f32) -> f32
Swaps the current value with a new value, returning the old value.
§Memory Ordering
Uses AcqRel ordering on the underlying AtomicU32. This provides
full synchronization for this read-modify-write operation.
§Parameters
value- The new value to swap in.
§Returns
The old value.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<f32>::new(1.0);
let old = atomic.swap(2.0);
assert_eq!(old, 1.0);
assert_eq!(atomic.load(), 2.0);Sourcepub fn compare_set(&self, current: f32, new: f32) -> Result<(), f32>
pub fn compare_set(&self, current: f32, new: f32) -> Result<(), f32>
Compares and sets the value atomically.
If the current value equals current, sets it to new and returns
Ok(()). Otherwise, returns Err(actual) where actual is the
current value.
Comparison uses the exact raw bit pattern produced by
f32::to_bits, not PartialEq.
§Memory Ordering
- Success: Uses
AcqRelordering on the underlyingAtomicU32to ensure full synchronization when the exchange succeeds. - Failure: Uses
Acquireordering to observe the actual value written by another thread.
§Parameters
current- The expected current value.new- The new value to set if current matches.
§Returns
Ok(()) when the value was replaced.
§Errors
Returns Err(actual) with the observed value when the raw-bit
comparison fails. In that case, new is not stored.
§Warning
NaN values compare by raw bits. A stored NaN and current must have
the same payload bits for the CAS to succeed.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<f32>::new(1.0);
assert!(atomic.compare_set(1.0, 2.0).is_ok());
assert_eq!(atomic.load(), 2.0);Sourcepub fn compare_set_weak(&self, current: f32, new: f32) -> Result<(), f32>
pub fn compare_set_weak(&self, current: f32, new: f32) -> Result<(), f32>
Weak version of compare-and-set.
May spuriously fail even when the comparison succeeds. Should be used in a loop.
Uses AcqRel ordering on success and Acquire ordering on failure.
Comparison uses the exact raw bit pattern produced by
f32::to_bits.
§Parameters
current- The expected current value.new- The new value to set if current matches.
§Returns
Ok(()) when the value was replaced.
§Errors
Returns Err(actual) with the observed value when the raw-bit
comparison fails, including possible spurious failures. In that case,
new is not stored.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<f32>::new(1.0);
let mut current = atomic.load();
loop {
match atomic.compare_set_weak(current, current + 1.0) {
Ok(_) => break,
Err(actual) => current = actual,
}
}
assert_eq!(atomic.load(), 2.0);Sourcepub fn compare_and_exchange(&self, current: f32, new: f32) -> f32
pub fn compare_and_exchange(&self, current: f32, new: f32) -> f32
Compares and exchanges the value atomically, returning the previous value.
If the current value equals current, sets it to new and returns
the old value. Otherwise, returns the actual current value.
Uses AcqRel ordering on success and Acquire ordering on failure.
§Parameters
current- The expected current value.new- The new value to set if current matches.
§Returns
The value observed before the operation completed. If the returned
value has the same raw bits as current, the exchange succeeded;
otherwise it is the actual value that prevented the exchange.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<f32>::new(1.0);
let prev = atomic.compare_and_exchange(1.0, 2.0);
assert_eq!(prev, 1.0);
assert_eq!(atomic.load(), 2.0);Sourcepub fn compare_and_exchange_weak(
&self,
current: f32,
new: f32,
) -> Result<f32, f32>
pub fn compare_and_exchange_weak( &self, current: f32, new: f32, ) -> Result<f32, f32>
Weak version of compare-and-exchange.
May spuriously fail even when the comparison succeeds. Should be used in a loop.
Uses AcqRel ordering on success and Acquire ordering on failure.
§Parameters
current- The expected current value.new- The new value to set if current matches.
§Returns
Ok(previous) when the value was replaced, or Err(actual) when the
comparison failed, including possible spurious failure. Values preserve
their exact raw bit patterns.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<f32>::new(1.0);
let mut current = atomic.load();
loop {
match atomic.compare_and_exchange_weak(current, current + 1.0) {
Ok(_) => break,
Err(actual) => current = actual,
}
}
assert_eq!(atomic.load(), 2.0);Sourcepub fn fetch_add(&self, delta: f32) -> f32
pub fn fetch_add(&self, delta: f32) -> f32
Atomically adds a value, returning the old value.
§Memory Ordering
Internally uses a CAS loop with compare_set_weak, which uses
AcqRel on success and Acquire on failure. The loop ensures
eventual consistency even under high contention.
§Performance
May be slow in high-contention scenarios due to the CAS loop. Consider using atomic integers if performance is critical.
§Parameters
delta- The value to add.
§Returns
The old value before adding.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<f32>::new(10.0);
let old = atomic.fetch_add(5.5);
assert_eq!(old, 10.0);
assert_eq!(atomic.load(), 15.5);Sourcepub fn fetch_sub(&self, delta: f32) -> f32
pub fn fetch_sub(&self, delta: f32) -> f32
Atomically subtracts a value, returning the old value.
§Memory Ordering
Internally uses a CAS loop with compare_set_weak, which uses
AcqRel on success and Acquire on failure. The loop ensures
eventual consistency even under high contention.
§Parameters
delta- The value to subtract.
§Returns
The old value before subtracting.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<f32>::new(10.0);
let old = atomic.fetch_sub(3.5);
assert_eq!(old, 10.0);
assert_eq!(atomic.load(), 6.5);Sourcepub fn fetch_mul(&self, factor: f32) -> f32
pub fn fetch_mul(&self, factor: f32) -> f32
Atomically multiplies by a factor, returning the old value.
§Memory Ordering
Internally uses a CAS loop with compare_set_weak, which uses
AcqRel on success and Acquire on failure. The loop ensures
eventual consistency even under high contention.
§Parameters
factor- The factor to multiply by.
§Returns
The old value before multiplying.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<f32>::new(10.0);
let old = atomic.fetch_mul(2.5);
assert_eq!(old, 10.0);
assert_eq!(atomic.load(), 25.0);Sourcepub fn fetch_div(&self, divisor: f32) -> f32
pub fn fetch_div(&self, divisor: f32) -> f32
Atomically divides by a divisor, returning the old value.
§Memory Ordering
Internally uses a CAS loop with compare_set_weak, which uses
AcqRel on success and Acquire on failure. The loop ensures
eventual consistency even under high contention.
§Parameters
divisor- The divisor to divide by.
§Returns
The old value before dividing.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<f32>::new(10.0);
let old = atomic.fetch_div(2.0);
assert_eq!(old, 10.0);
assert_eq!(atomic.load(), 5.0);Sourcepub fn fetch_update<F>(&self, f: F) -> f32
pub fn fetch_update<F>(&self, f: F) -> f32
Updates the value using a function, returning the old value.
§Memory Ordering
Internally uses a CAS loop with compare_set_weak, which uses
AcqRel on success and Acquire on failure. The loop ensures
eventual consistency even under high contention.
§Parameters
f- A function that takes the current value and returns the new value.
§Returns
The old value before the update.
The closure may be called more than once when concurrent updates cause CAS retries.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<f32>::new(10.0);
let old = atomic.fetch_update(|x| x * 2.0);
assert_eq!(old, 10.0);
assert_eq!(atomic.load(), 20.0);Sourcepub fn update_and_get<F>(&self, f: F) -> f32
pub fn update_and_get<F>(&self, f: F) -> f32
Updates the value using a function, returning the new value.
Internally uses a CAS loop until the update succeeds.
§Parameters
f- A function that takes the current value and returns the new value.
§Returns
The value committed by the successful update.
The closure may be called more than once when concurrent updates cause CAS retries.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<f32>::new(10.0);
let new = atomic.update_and_get(|x| x * 2.0);
assert_eq!(new, 20.0);
assert_eq!(atomic.load(), 20.0);Sourcepub fn try_update<F>(&self, f: F) -> Option<f32>
pub fn try_update<F>(&self, f: F) -> Option<f32>
Conditionally updates the value using a function.
Internally uses a CAS loop until the update succeeds or the closure
rejects the current value by returning None.
§Parameters
f- A function that takes the current value and returns the new value, orNoneto leave the value unchanged.
§Returns
Some(old_value) when the update succeeds, or None when f rejects
the observed current value.
The closure may be called more than once when concurrent updates cause CAS retries.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<f32>::new(1.5);
assert_eq!(atomic.try_update(|x| (x > 0.0).then_some(x * 2.0)), Some(1.5));
assert_eq!(atomic.load(), 3.0);
assert_eq!(atomic.try_update(|x| (x < 0.0).then_some(x * 2.0)), None);
assert_eq!(atomic.load(), 3.0);Sourcepub fn try_update_and_get<F>(&self, f: F) -> Option<f32>
pub fn try_update_and_get<F>(&self, f: F) -> Option<f32>
Conditionally updates the value using a function, returning the new value.
Internally uses a CAS loop until the update succeeds or the closure
rejects the current value by returning None.
§Parameters
f- A function that takes the current value and returns the new value, orNoneto leave the value unchanged.
§Returns
Some(new_value) when the update succeeds, or None when f rejects
the observed current value.
The closure may be called more than once when concurrent updates cause CAS retries.
§Example
use qubit_atomic::Atomic;
let atomic = Atomic::<f32>::new(1.5);
assert_eq!(
atomic.try_update_and_get(|x| (x > 0.0).then_some(x * 2.0)),
Some(3.0),
);
assert_eq!(atomic.load(), 3.0);
assert_eq!(
atomic.try_update_and_get(|x| (x < 0.0).then_some(x * 2.0)),
None,
);
assert_eq!(atomic.load(), 3.0);Sourcepub fn inner(&self) -> &AtomicU32
pub fn inner(&self) -> &AtomicU32
Gets a reference to the underlying standard library atomic type.
This allows direct access to the standard library’s atomic operations for advanced use cases that require fine-grained control over memory ordering.
§Memory Ordering
When using the returned reference, you have full control over memory
ordering. Remember to use f32::to_bits() and f32::from_bits() for
conversions.
§Returns
A reference to the underlying std::sync::atomic::AtomicU32.
§Example
use qubit_atomic::Atomic;
use std::sync::atomic::Ordering;
let atomic = Atomic::<f32>::new(0.0);
atomic.inner().store(3.14_f32.to_bits(), Ordering::Relaxed);
let bits = atomic.inner().load(Ordering::Relaxed);
assert_eq!(f32::from_bits(bits), 3.14);