This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
MCuniverse's profile picture

Loop errors, works fine on first loop

Started by MCuniverse, 03 March 2014 - 11:12 AM
MCuniverse #1
Posted 03 March 2014 - 12:12 PM
Code:
http://pastebin.com/HwJkm6bk (before)
http://pastebin.com/6Ci3iSVw (current)

I am starting to work again on the GiantMath structure (in an attempt to perform larger math via tables instead of whole digits). I have encountered a problem which can be traced to the mul() function. Upon running the test program (test it by typing in the filename), it says "1 2 3 4 1" then an error " attempt to perform arithmetic __add on nil and number ". The only thing is I do not remember setting any of my tables to get set to nil. What's more strange is that it occurs on check(), where it successfully runs on the first loop.
Edited on 05 March 2014 - 06:16 AM
CometWolf #2
Posted 03 March 2014 - 02:53 PM
Quick note, the tablen function is uttely redundant.

function tablen(ntable)
  local i = 0
  while true do
    i = i + 1
    if ntable[i] == nil then
	  return i-1
    end
  end
end
Doing the following, would yield the same result

#ntable

Anyways, a quick check of your variables reveals that "itst-1 = 0", and your tables don't appear to be indexed from 0.

function check(ntable)

  --Carryout
  local i = 0
  repeat
    i = i + 1
    local itst = tablen(ntable) - (i - 1)
    if ntable[itst] >= 10 then
	
	  local ndivide = math.floor(ntable[itst] / 10)
	  local nmod = ntable[itst] % 10
	
	  ntable[itst] = nmod
	  ntable[itst-1] = ntable[itst-1] + ndivide -- the line causing your error
	  move(ntable)
	
	  --Can also be used for transforming whole
	  --numbers into segmented table numbers
    end
  until i == tablen(ntable)

Since math isn't really my area, and as such won't be going to in-depth in this code, i proppose the following fix.

function check(ntable)

  --Carryout
  local i = 0
  repeat
    i = i + 1
    local itst = tablen(ntable) - (i - 1)
    if ntable[itst] >= 10 and itst > 1 then -- see here
	
	  local ndivide = math.floor(ntable[itst] / 10)
	  local nmod = ntable[itst] % 10
	
	  ntable[itst] = nmod
	  ntable[itst-1] = ntable[itst-1] + ndivide
	  move(ntable)
	
	  --Can also be used for transforming whole
	  --numbers into segmented table numbers
    end
  until i == tablen(ntable)
This does however cause a BIOS error, because some function is expecting a string somewhere. From what i can tell, this error is caused by the write function at the bottom, probably cause there is no num3[8]. changing the loop to the following fixes that though

for i = 1, #num3 do
  write(num3[i])
end
This prints the end result as 8945336, idk if that's correct or not.
MCuniverse #3
Posted 03 March 2014 - 02:59 PM
Quick note, the tablen function is uttely redundant.

function tablen(ntable)
  local i = 0
  while true do
	i = i + 1
	if ntable[i] == nil then
	  return i-1
	end
  end
end
Doing the following, would yield the same result

#ntable

Anyways, a quick check of your variables reveals that "itst-1 = 0", and your tables don't appear to be indexed from 0.

function check(ntable)

  --Carryout
  local i = 0
  repeat
	i = i + 1
	local itst = tablen(ntable) - (i - 1)
	if ntable[itst] >= 10 then
	
	  local ndivide = math.floor(ntable[itst] / 10)
	  local nmod = ntable[itst] % 10
	
	  ntable[itst] = nmod
	  ntable[itst-1] = ntable[itst-1] + ndivide -- the line causing your error
	  move(ntable)
	
	  --Can also be used for transforming whole
	  --numbers into segmented table numbers
	end
  until i == tablen(ntable)

Since math isn't really my area, and as such won't be going to in-depth in this code, i proppose the following fix.

function check(ntable)

  --Carryout
  local i = 0
  repeat
	i = i + 1
	local itst = tablen(ntable) - (i - 1)
	if ntable[itst] >= 10 and itst > 1 then -- see here
	
	  local ndivide = math.floor(ntable[itst] / 10)
	  local nmod = ntable[itst] % 10
	
	  ntable[itst] = nmod
	  ntable[itst-1] = ntable[itst-1] + ndivide
	  move(ntable)
	
	  --Can also be used for transforming whole
	  --numbers into segmented table numbers
	end
  until i == tablen(ntable)
This does however cause a BIOS error, because some function is expecting a string somewhere. From what i can tell, this error is caused by the write function at the bottom, probably cause there is no num3[8]. changing the loop to the following fixes that though

for i = 1, #num3 do
  write(num3[i])
end
This prints the end result as 8945336, idk if that's correct or not.
Nope, not gonna work. Result should be 10353116. Also, I simply put that there because I forgot what the table variable function was. Simplifying it.
Edited on 03 March 2014 - 02:01 PM
Bomb Bloke #4
Posted 03 March 2014 - 03:01 PM
It's basically trying to carry numbers to a lower array element, which has the potential to be 0, but you can't add to an undefined slot (number + nil = error).

Putting "if not ntable[itst-1] then ntable[itst-1] = 0 end" just before line 73 should sort that particular error properly, but the move() function will also need to be re-written to match (that cannot just attempt to delete ntable[0] without moving it!).

Speaking of deleting array elements, this:

  if ntable[0] ~= nil then
    table.insert(ntable, 0, "nil")
  end

… won't do the trick, but rather will insert a string containing the text "nil" into that index. A better way would be:

  if ntable[0] ~= nil then
    ntable[0] = nil
  end
MCuniverse #5
Posted 04 March 2014 - 04:55 AM
It's basically trying to carry numbers to a lower array element, which has the potential to be 0, but you can't add to an undefined slot (number + nil = error).

Putting "if not ntable[itst-1] then ntable[itst-1] = 0 end" just before line 73 should sort that particular error properly, but the move() function will also need to be re-written to match (that cannot just attempt to delete ntable[0] without moving it!).

Speaking of deleting array elements, this:

  if ntable[0] ~= nil then
	table.insert(ntable, 0, "nil")
  end

… won't do the trick, but rather will insert a string containing the text "nil" into that index. A better way would be:

  if ntable[0] ~= nil then
	ntable[0] = nil
  end
It has helped a bit, but I'm getting the wrong results.
Bomb Bloke #6
Posted 04 March 2014 - 09:49 AM
At a glance, the code in your pastebin appears the same? I'll need to see your changes to comment on whether they're sufficient / correct.
MCuniverse #7
Posted 05 March 2014 - 07:17 AM
There, I added the renovated (still incorrect) version.
Bomb Bloke #8
Posted 05 March 2014 - 11:36 PM
Your move() function is still outright deleting whatever's in ntable[0], even though you're using that to store information essential to the calculation. I may not've stressed this enough before, but you just can't do that! Let's run through the logic of the program to make it clear as to why.

Say you've got your two numbers, 4321 and 6932. These get converted into tables such that num[1] = 4, num[2] = 3, etc, and num2[1] = 6, num2[2] = 9, etc. Note here that the rule you're using is that the lower the index, the higher the value of the digit.

You pass these tables to your mul() function. For each digit in num2, it generates a "calc" table:

	for i21 = 1, #num do
	  calc[i21] = num[i21] * num2[i1]
	  check(calc)
	end

On the first iteration, calc[1] = num[1] * num2[1], which is 4 * 6 = 24. In case we've now got more then one digit stored in that index (which, as it happens, we do), this gets "checked".

Now, to go on a slight tangent, when you pass "calc" to "check()" that function gets handed a pointer to the actual "calc" table (if it were a different variable type, like a number, it'd just pass the number; with tables, you get a pointer).

It sticks that pointer in "ntable", but that variable still leads to the same table - any changes it makes to "ntable" are reflected in "calc" because the two variables literally lead to the same area of memory. This is worth mentioning, because when you call "check()" you don't actually save what it returns. The only reason it does anything is because of the way the table pointers work. "check()" could have its "return" statement removed completely and it'd work just the same. Ditto for "move()".

Anyway, "check()" notices that calc[1] exceeds ten. It hence sets calc[1] to 4, and sets the next lowest index - calc[0] - to 2.

Then you call "move()" on that result, which spots that calc[0] isn't nil and… simply deletes it. So now your calc table consists soley of this:

calc[1] = 4

Hopefully this makes it clear what you need to do - your "move()" function currently only moves digits one way, which happens not to be the direction we need it to be in this instance.

Edit:

Bear in mind that I'm being coy; the answer is fairly simple, I just feel you should be able to spot it. ;)/>

But I suppose it's unfair not to point out that your initial attempt at the move() function did go in both directions - it just left a dirty great string in calc[0]. "nil" isn't the same thing as nil.

Another point: Bear in mind that if, say, after moving you get a table that looks like this:

calc[1] = 2
calc[2] = 4

… the first bit of code I quoted will, on its second iteration, overwrite calc[2] with something else. You may want to rig it like this:

	for i21 = 1, #num do
	  calc[i21] = num[i21] * num2[i1]
	end
	check(calc)

… which will require you to make the "check" function count backwards through the digits.
Edited on 06 March 2014 - 12:08 AM