如何用Python将数值范围按指数方式转换到另一目标范围?
Hey there! Since you already grasp linear normalization, we can build directly on that to nail the exponential mapping you need. Let’s break this down into simple, actionable steps that don’t require fancy math jargon.
Core Idea
Exponential mapping follows three straightforward stages—we’re just adding a "curve" to the linear normalization you already know:
- Shrink your input value from [A,B] down to the 0-1 range (same as linear normalization).
- Bend this normalized value with an exponent to create the exponential curve.
- Stretch the curved value back up to your target range [C,D].
Step-by-Step Breakdown
Let’s define each part clearly, with plain language:
- Let
xbe your input value sitting in the original range [A,B] kis your "curve control" parameter:k > 1: Squishes values closer to A, and stretches values closer to B (great if you want to emphasize higher-end values)0 < k < 1: Squishes values closer to B, and stretches values closer to A (perfect for emphasizing lower-end values)k = 1: This turns into plain linear normalization (a great sanity check to make sure things work!)
1. Normalize to 0-1 Range
First, we shrink your input to a simple 0-to-1 scale—this part you already know:
x_norm = (x - A) / (B - A)
We’ll handle the edge case where A equals B (all inputs are the same) in the full function below.
2. Apply the Exponential Curve
Next, we bend the normalized value using the exponent k:
x_exp = x_norm ** k
This is where the magic happens—this exponent is what creates the non-linear "stretch" or "squish".
3. Map to Target Range [C,D]
Finally, we scale the curved value up to your desired target range:
x_final = C + (D - C) * x_exp
Full Python Function
Here’s a robust, user-friendly function that handles edge cases and lets you control whether values outside [A,B] stay within [C,D] (clamping):
def exponential_map(x, A, B, C, D, k=2.0, clamp=True): # Handle the case where original range is a single value (A == B) if A == B: return (C + D) / 2 # Return midpoint of target range; adjust if needed # Step 1: Shrink input to 0-1 range x_norm = (x - A) / (B - A) # Optional: Keep values within 0-1 to avoid exceeding target range if clamp: x_norm = max(0.0, min(1.0, x_norm)) # Step 2: Apply the exponential curve x_exp = x_norm ** k # Step 3: Stretch to target range [C,D] x_final = C + (D - C) * x_exp return x_final
Example Usage
Let’s test this with concrete numbers to see how it behaves:
- Original range:
A=0, B=10 - Target range:
C=0, D=100 - Exponent:
k=2
# Input x=5 (midpoint of original range) print(exponential_map(5, 0, 10, 0, 100, k=2)) # Output: 25.0 (squished toward lower end) # Input x=8 (closer to B) print(exponential_map(8, 0, 10, 0, 100, k=2)) # Output: 64.0 (stretched toward higher end) # Try k=0.5 (reverse curve) print(exponential_map(5, 0, 10, 0, 100, k=0.5)) # Output: ~70.7 (stretched toward lower end)
Bonus: Reverse Mapping
If you ever need to convert a value from [C,D] back to [A,B], just reverse the steps:
def reverse_exponential_map(x_final, A, B, C, D, k=2.0, clamp=True): if C == D: return (A + B) / 2 x_exp_norm = (x_final - C) / (D - C) if clamp: x_exp_norm = max(0.0, min(1.0, x_exp_norm)) x_norm = x_exp_norm ** (1/k) x = A + (B - A) * x_norm return x
Play around with different k values to get the exact curve you need—small adjustments can make a big difference!
内容的提问来源于stack exchange,提问作者NoSplitSherlock

