<Range> Node

Tags: #<Tag:0x00007fa12d0cacf8>

Hi Nick,

The only scaling in the formula for the “single-sided” case is what is necessary for the bit-depth scaling. I think there is a logic to that since you would need “both sides” in order to infer both a non-default scaling and an offset. So the “single-sided” case is basically a simple offset that is corrected for any bit-depth difference. So in your example, maxInValue does get mapped to maxOutValue, which I think is the primary expectation. Your example input value of 0.5, which is 1.5 less than maxInValue, gets mapped to 8.5, which is 1.5 less than maxOutValue. So I think it is a plausible result.

But as I wrote farther up in this thread, I agree that the “single-sided” case is probably not very useful for anything other than a simple clamp. In fact, in the interest of moving this forward and trying to bring us to consensus, I’ll go ahead and make a concrete proposal:

In Scott’s PDF on OverLeaf referenced earlier in the thread, change equation 3 from:

out = MAX(minOutValue, in × scale + minOutValue − minInValue × scale)

to simply:

out = MAX(minOutValue, in × scale)

and change equation 4 to:

out = MIN(maxOutValue, in × scale)

And add a note such as

Note: If only the minimum values are specified, the values must be set such that minOutValue = minInValue × scale. Likewise, if only the maximum values are specified, the values must be set such that maxOutValue = maxInValue × scale.

(One could argue that only the minIn or minOut is necessary, but I think it is important for readability to include both.)

I think that would address the issue that you and Jim raised. (Yes?) It is a change from the v2 spec but it’s minor enough that I’m not aware of any real-world use-cases that would actually break due to that change.

Regarding your other post about scaling, I agree that sentence is confusing. Actually, I don’t think that sentence is even necessary so perhaps the best thing is just to delete it.


I think it would address the issue, as long as it is clearly documented. Currently it is slightly unclear whether the document is user-facing or developer-facing. From a user perspective it would be easy to make assumptions about expected behaviour, such as implicit minimum values of zero when omitted. It would be better if the behaviour was clearly described in the text. At the moment, it is necessary to run various numbers through the provided equations (as @jim_houston and I did) to find out what the behaviour is.

Plausible, yes, once you analyse what the maths does. But I don’t think that a pure offset, based only on the difference between in and out values is what people would necessarily intuitively expect from an operator called “Range”.

out = min(in, maxInValue) * (maxOutValue / maxInValue)

is the maths I would intuitively expect, as only scaling seems more logical to me than only offsetting.

However there is no obvious equivalent for minimums only, particularly as those could often both be zero.

1 Like

No for sure! To me and without looking at the doc I would expect it to be equivalent to those:



To be clear, it is equivalent to those when all four values are given. It is the behaviour when only two are given which is perhaps not intuitive.

Argggg, I have been beaten at the explicitness game :slight_smile: What I was trying to imply is that all the functions I mentioned require explicit in/source and out/destination ranges.

Yes, it’s really just CLF’s use of only Min or Max values in the Range node as a special case to perform one-sided clamping, simply to avoid having a dedicated Clamp operator, which introduces the potential confusion, I think.

1 Like

Right, so hopefully my proposal helps since it removed the ability to use the single-sided case to do an offset.

Thanks for the links to the other examples Thomas.


" 1. Fundamentally, the spec provides two ways of applying a shift and scale operation: Matrix and Range. The difference is that the Matrix does not clamp and the Range does."

I like such simplicity.

In the middle of something else, so have not had time to check the proposal in the thread,

however, I can comment that the Spec is ‘developer-facing’ but mixed with information for a
LUT designer. So I can see where that can get unclear. Doug’s CTF web pages are a much better user
description of the nodes for example.

On the in-depth, out-depth question, the sentence is part of a paragraph, and the whole paragraph is the situation being dealt with (again for the missing end case as a default) not a problem when all four elements are defined:

" If the input and output bit depths are not the same, a conversion should take place using the range elements. If the elements defining an InValue range or OutValue range are not provided, then the default behavior is to use the full range available with the inBitDepth or outBitDepth attribute used in place of the
missing input range or missing output range, respectively, as calculated with these equations:”

I agree with Nick’s statement of what the expected behavior, and yes this is mostly
about what happens when either the minValue or maxValue is missing.

The Range Node is about mapping one range to another, but especially allowing
the ability to select a floating range including negatives and map it to a different
floating point range. so a {-1000,1000) should be able to map to a {1000,3000}.
In this case, the scale=1, but the other term is { in + 2000 } to offset to the right place
in the new range. Doug’s modified eqn would just echo the ‘in’ value and clamp it against
the MIN or MAX. This is still the wrong result. Nick’s modification also only focuses on ‘scale’
when both scale+offset are needed.

The ‘special math’ at the end for missing entries does not do this.

I still recommend

A) deleting this ‘missing elements’ section and requiring all four entries and indicating CLAMPs explicitly.
B) creating a RANGEF node that mandates only the basic equation and no missing entries for floating point.


I would note one other small bug…

the rangescaler for integers has a - 1 that should not be there.
the Pure ints 12i/10i 4096/1024 = 4 X for the scaler which is correct.
The minus 1 gives 4095/1023 = 4.002932 which is incorrect.