#298 Aug 4, 2026

298. copysign — Stamp One Number's Sign Onto Another, Sign Bit and All

Bite 297 showed signum reading the sign bit. copysign is the other half: it writes one — take this magnitude, give it that number’s sign, one call.

The branch

You have a fixed magnitude and a direction living in another variable — a step size, a force, a correction — and out comes the same conditional every time:

1
2
3
let delta: f64 = -3.2;

let step = if delta < 0.0 { -0.25 } else { 0.25 };

One call

1
2
3
4
5
let step = 0.25_f64.copysign(delta); // -0.25

assert_eq!(3.5_f64.copysign(-1.0), -3.5);
assert_eq!((-3.5_f64).copysign(1.0), 3.5);
assert_eq!(7.0_f64.copysign(2.0), 7.0);

The receiver contributes the magnitude, the argument contributes the sign. Yesterday’s “step toward the target” loop works for floats too — magnitude from you, direction from the gap:

1
2
3
4
5
6
7
let mut pos = 1.0_f64;
let target = 2.0;

while (target - pos).abs() >= 0.25 {
    pos += 0.25_f64.copysign(target - pos);
}
assert_eq!(pos, 2.0); // 0.25 divides 1.0 exactly

It really is the sign bit

Like f64::signum, copysign works on the raw sign bit — which is exactly what makes it more honest than the if:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// the branch calls -0.0 "positive"...
let x = -0.0_f64;
let s = if x < 0.0 { -1.0 } else { 1.0 };
assert_eq!(s, 1.0);

// ...copysign actually looks at the bit
assert!(1.0_f64.copysign(-0.0).is_sign_negative());

// and a NaN's magnitude stays NaN, sign still applied
assert!(f64::NAN.copysign(-1.0).is_sign_negative());

Anywhere you’re bolting a direction onto a magnitude — drag opposing velocity, rounding away from zero, mirroring a coordinate — copysign is the branch-free, -0.0-correct way to say it.

← Previous 297. signum — The -1 / 0 / +1 You Keep Building With an If-Else Ladder Next → 299. hypot — The Distance Formula That Doesn't Overflow