Python math.copysign(): Copy Sign Bit Between Numbers

The math.copysign(x, y) function returns a floating-point number having the magnitude (absolute value) of x but the sign of y. Regardless of whether integer or floating-point arguments are passed, math.copysign() always returns a float.

IEEE 754 Signed Zero Support: Unlike standard comparison operators (y < 0), math.copysign() inspects the underlying hardware sign bit directly. It can detect and transfer the sign of IEEE 754 negative zero (-0.0), making math.copysign(1.0, -0.0) == -1.0.

Syntax & Parameters 🔝

The math.copysign() function is part of Python's built-in math module and maps directly to the C library copysign() function:

import math

math.copysign(x, y)
Parameter Type Description
x float or int Required. The magnitude (absolute value) source.
y float or int Required. The sign source. Its sign bit is applied to the magnitude of x.
Return Value float A 64-bit float equal to |x| if y ≥ 0, or -|x| if y ≤ -0.0.
TypeError Exception Raised when either argument is non-numeric (e.g. strings or lists).

Basic Usage & Sign Transfer Examples 🔝

Examine how the four combinations of positive and negative inputs behave:

import math

# Positive magnitude, Negative sign
print("copysign(3, -2): ", math.copysign(3, -2))   # Output: -3.0

# Negative magnitude, Negative sign
print("copysign(-3, -2):", math.copysign(-3, -2))  # Output: -3.0

# Negative magnitude, Positive sign
print("copysign(-3, 2): ", math.copysign(-3, 2))   # Output: 3.0

# Positive magnitude, Positive sign
print("copysign(3, 2):  ", math.copysign(3, 2))    # Output: 3.0

# Always returns a float, even for pure integer inputs
val = math.copysign(10, 1)
print("Type of return:", type(val), "Value:", val)

Output:

copysign(3, -2):  -3.0
copysign(-3, -2): -3.0
copysign(-3, 2):  3.0
copysign(3, 2):   3.0
Type of return: <class 'float'> Value: 10.0

You can also use math.copysign() to adjust a list of numeric features in a dataset:

raw_measurements = [12.5, -8.4, 19.0, -3.2]
forced_negative = [math.copysign(x, -1) for x in raw_measurements]
print("Forced negative:", forced_negative)

Output:

Forced negative: [-12.5, -8.4, -19.0, -3.2]

Detecting IEEE 754 Negative Zero (-0.0) 🔝

In the IEEE 754 floating-point standard used by Python, floating-point numbers have a dedicated sign bit. Consequently, zero exists in two distinct representations: positive zero (+0.0) and negative zero (-0.0).

According to the standard, numerical equality evaluates 0.0 == -0.0 as True, and inequality -0.0 < 0.0 as False. Because ordinary comparison operators cannot distinguish between positive and negative zero, math.copysign() is the standard, canonical tool to test whether a float is negative zero:

import math

pos_zero = 0.0
neg_zero = -0.0

print("Are they numerically equal? ", pos_zero == neg_zero)      # True
print("Is neg_zero < 0.0?           ", neg_zero < 0.0)           # False!

# Using math.copysign to inspect the sign bit
print("copysign(1.0, pos_zero):     ", math.copysign(1.0, pos_zero))  # 1.0
print("copysign(1.0, neg_zero):     ", math.copysign(1.0, neg_zero))  # -1.0

def is_negative_zero(val):
    return val == 0.0 and math.copysign(1.0, val) < 0.0

print("is_negative_zero(0.0):       ", is_negative_zero(pos_zero))  # False
print("is_negative_zero(-0.0):      ", is_negative_zero(neg_zero))  # True

Output:

Are they numerically equal?  True
Is neg_zero < 0.0?           False
copysign(1.0, pos_zero):      1.0
copysign(1.0, neg_zero):      -1.0
is_negative_zero(0.0):        False
is_negative_zero(-0.0):       True
Why Negative Zero Matters in Science & Physics: When dividing by zero, the sign determines the direction of infinity: 1.0 / 0.0 yields +inf, whereas 1.0 / -0.0 yields -inf. In complex analysis, branch cuts across the negative real axis depend on whether zero was approached from above (+0.0j) or below (-0.0j).

math.copysign() vs. abs() and Ternary Conditions 🔝

Many programmers attempt to copy signs using conditional expressions or mathematical multiplication:

# Flawed manual pattern:
manual_result = abs(x) if y >= 0 else -abs(x)

This manual pattern suffers from two major flaws:

  1. Fails on Negative Zero: When y = -0.0, the condition -0.0 >= 0 evaluates to True, incorrectly producing a positive result instead of negative.
  2. Performance Overhead: The manual approach requires conditional branching and magnitude recalculation. math.copysign() executes a single bitwise instruction at the CPU hardware level, clearing and setting the sign bit directly.

Special Values: Infinities and NaNs 🔝

Python's math.copysign() handles special IEEE 754 floating-point entities with total consistency:

Expression Result Explanation
math.copysign(float('inf'), -1) -inf Infinite magnitude with negative sign.
math.copysign(5.0, float('-inf')) -5.0 Negative sign extracted from negative infinity.
math.copysign(float('nan'), -1) nan (with sign bit set) NaN magnitude with sign bit updated.
math.copysign(0.0, -1) -0.0 Returns signed negative zero.
import math

print("copysign(inf, -1): ", math.copysign(float('inf'), -1))
print("copysign(5.0, -inf):", math.copysign(5.0, float('-inf')))
print("copysign(0.0, -1):  ", math.copysign(0.0, -1))

Output:

copysign(inf, -1):  -inf
copysign(5.0, -inf): -5.0
copysign(0.0, -1):   -0.0

Hands-on Exercise: 1D Kinematic Physics Vector Engine with Assertions 🔝

In physics simulations, robotics, and game engines, speeds are calculated as positive scalar magnitudes (e.g. from throttle or energy conservation), while directions are computed from displacement vectors. math.copysign() is the standard tool to merge scalar speed with directional vectors:

  1. Directional Velocity: Given a scalar speed magnitude |v| ≥ 0 and a displacement offset dx = target_x - current_x, the velocity is v = copysign(|v|, dx).
  2. Elastic Collision Bounce: When a projectile with velocity v strikes a vertical barrier with restitution coefficient e (where 0 < e ≤ 1), the rebounded velocity reverses direction: v_new = copysign(e * |v|, -v).
Python Exercise: Kinematic Velocity & Rebound Engine
import math

def calculate_directed_velocity(speed, target_x, current_x):
    """Applies the direction of displacement (target - current) to a scalar speed."""
    if speed < 0:
        raise ValueError("Speed magnitude must be non-negative.")
    displacement = target_x - current_x
    return math.copysign(speed, displacement)

def simulate_rebound(velocity, restitution=0.8):
    """Reverses velocity direction after striking a barrier, applying restitution damping."""
    if not (0.0 <= restitution <= 1.0):
        raise ValueError("Restitution coefficient must be between 0.0 and 1.0.")
    rebounded_speed = abs(velocity) * restitution
    # Reverse sign of incident velocity
    return math.copysign(rebounded_speed, -velocity)

# Unit Assertions
# Moving forward towards target
assert calculate_directed_velocity(25.0, 100.0, 40.0) == 25.0

# Moving backward towards target behind
assert calculate_directed_velocity(25.0, 10.0, 40.0) == -25.0

# Rebound checks
assert simulate_rebound(50.0, 0.8) == -40.0
assert simulate_rebound(-40.0, 0.5) == 20.0

# Preserving zero velocity
assert simulate_rebound(0.0, 0.8) == -0.0

print("Directed velocity towards x=10m:", calculate_directed_velocity(15.0, 10.0, 50.0))
print("Rebound from +30 m/s barrier:   ", simulate_rebound(30.0, 0.75))
print("All kinematic physics assertions passed successfully!")

Practice in Google Colab & GitHub 🔝

Open in Google Colab View on GitHub

Run all math.copysign() examples interactively, test IEEE 754 negative zero detection, inspect infinity and NaN behaviors, and simulate 1D kinematic physics collisions in Google Colab.




Subscribe to our YouTube Channel here



plus2net.com







Python Video Tutorials
Python SQLite Video Tutorials
Python MySQL Video Tutorials
Python Tkinter Video Tutorials
✖
We use cookies to improve your browsing experience. . Learn more
HTML MySQL PHP JavaScript ASP Photoshop Articles Contact us
© 2000-2026 plus2net.com All rights reserved worldwide Privacy Policy Disclaimer