Impossible error occuring?

Hello,

I’ve ran into an issue that i’ve been debugging for the past hour with no success. A function that I’ve created, InverseLerp, is supposed to return a value [0, 1] depending on where Value is inbetween From and To.

This, however, is not the case. Instead, the function returns nil!? I’m unsure how this is possible as the function returns something in every case, even if all if statements fail.


Use in script and proof that the arguments exist

local Alpha = InverseLerp(SmallestValue, LargestValue, HeightMap[X][Z])

image


Function - InverseLerp

function InverseLerp(From :number, To :number, Value :number)
	if From < To then      
		if Value < From then 
			return 0
		end

		if Value > To then      
			return 1
		end

		Value = Value - From
		Value = Value/(To - From)
		return Value
	end

	if From <= To then
		return 0
	end

	if Value < To then
		return 1
	end

	if Value > From then
		return 0
	end

	return 1.0 - ((Value - To) / (From - To))
end


The Issue


From all my tests, the function has a valid return UNLESS the From or To arguments are the same as the Value argument


This is probably a stupid caveat that I’ve overlooked but any help is appreciated!

1 Like

In my testing, I have failed to ever get a nil value.

function InverseLerp(From :number, To :number, Value :number)
	if From < To then      
		if Value < From then 
			return 0
		end

		if Value > To then      
			return 1
		end

		Value = Value - From
		Value = Value/(To - From)
		return Value
	end

	if From <= To then
		return 0
	end

	if Value < To then
		return 1
	end

	if Value > From then
		return 0
	end

	return 1.0 - ((Value - To) / (From - To))
end
print(InverseLerp(0.4991, 0.4991, 1.22323)) -- prints 0
print(InverseLerp(0.4991, 1.22323, 1.22323)) -- prints 1

Are you sure you aren’t making a mistake like printing the wrong value?

I’ve set the debugger print condition to be:

Alpha == nil 

And the print to be:

"Alpha is nil", SmallestValue, HeightMap[X][Y], LargestValue


image

weird edge case, but you only defined the function once, right?

Is there a reason why you have to use if statements? It’s an algebraic equation you can just rearrange the variables

math equations have conditionals too

I’m confident that this error is just breakpoints being fired when they shouldn’t be.

I ran your code in a test loop with your breakpoint slightly modified.

image

for i = 0, 10 do
	local small = math.random()
	local large = math.random()
	local value = math.random()
	
	local a = InverseLerp(small, large, value)
end

Which provides this output:

I then modified my code as such

local a

for i = 0, 10 do
	local small = math.random()
	local large = math.random()
	local value = math.random()
	
	a = InverseLerp(small, large, value)
end

Which changed the output drastically to this

I then further changed my code and breakpoint

image

for i = 0, 10 do
	local small = math.random()
	local large = math.random()
	local value = math.random()
	
	local b = InverseLerp(small, large, value)
	a = b
end

What conclusion do I draw from this? You’re running into this issue because your “alpha” value is initialized as nil, then set to a function call. However, it would seem that breakpoints fire as soon as their condition is met, even if the line they are attached to has not fully executed.

Is this intended? Maybe not. Is it weird? Yes. Is your code flawed with some really rare bug? Most definitely not.

1 Like

No they don’t. If his whole thing was sometimes it wouldn’t be exactly 0 or 1 then he could do this

local function inverseLerp(from, to, value)
  local tolerance = 0.000001
  local step = (-from+value)/(-from+to)
  if step < tolerance then
    step = 0
  elseif 1-step < tolerance then
    step = 1
  end
  return step
end

Here is the section of the code:

-- ...

local function InverseLerp(From, To, Value)
    if From < To then      
		if Value < From then 
			return 0
		end

		if Value > To then      
			return 1
		end

		Value = Value - From
		Value = Value/(To - From)
		return Value
	end

	if From <= To then
		return 0
	end

	if Value < To then
		return 1
	end

	if Value > From then
		return 0
	end

	return 1.0 - ((Value - To) / (From - To))
end

-- ...

local MaterialMap = {}

-- ...


local Materials = {
	{Height = .90, Material = Enum.Material.Snow},
	{Height = .80, Material = Enum.Material.Rock},
	{Height = .50, Material = Enum.Material.Grass},
	{Height = .30, Material = Enum.Material.Sand},
	{Height = .10, Material = Enum.Material.Water}
}


-- ...

for X = 1, SizeX do -- SizeX is usually 200
	MaterialMap[X] = {}
	
	for Z = 1, SizeZ do -- SizeZ is usually 200
		local Alpha = InverseLerp(SmallestValue, LargestValue, HeightMap[X][Z]) -- Breakpoint prints nil if Value equal to From or To
		print(Alpha) -- also prints nil if Value equal to From or To
		-- Values that are not exactly equal to From or To usually return correctly (not nil)

		local Material = nil
		
		for _, Level in ipairs(Materials) do
			if Alpha > Level.Height then
				MaterialMap[X][Z] = Level.Material
				Material = Level.Material
				break
			end
		end
	end
end

for X = 1, SizeX do
	for Z = 1, SizeZ do
		local Material = MaterialMap[X][Z]
		local Y = HeightMap[X][Z]
		
		local Position = Vector3.new(X - (SizeX / 2), Y + (math.abs(SmallestValue) * 100), Z - (SizeZ / 2))
		local Orientation = CFrame.Angles(0, 0, 0)
		local Size = Vector3.new(1, 1, 1)
		
		local CoordinateFrame = CFrame.new(Position) * Orientation
		
		Terrain:FillBlock(CoordinateFrame, Size, Material) -- Error: Argument 3 missing or nil 
	end
end


image

I don’t think you’re setting every value in the MaterialMap because you’re only setting it if Alpha is > a Height from Materials, but ignoring the case where Alpha is 0.10 or lower

I’d output MaterialMap after the first outer loop

You are correct, I forgot to check if the value was bigger than or equal to the level’s height.