Log In  

hey is it just me or is sgn(0) returning 1 where it should return 0?
i get this with both literal 0 and 0 through arithmetic

P#15673 2015-10-21 04:50 ( Edited 2016-01-11 00:31)

P#15692 2015-10-21 13:48 ( Edited 2015-10-21 17:58)

ah. i guess i shouldn't hold out much hope for a fix soon then lol

P#15698 2015-10-21 14:07 ( Edited 2015-10-21 18:07)

I've seen both sgn(0)==1 and sgn(0)==0 in various code bases, and also less ambiguous versions: sgn0(), sgn2(), sgn3() that return 3, 2 and 3 possible values respectively. After a quick survey, it looks like sgn(0)==0 is more typical and maybe has some mathematical basis (?). It's still not too late to change the behaviour in pico-8 I think.

Just out of curiosity, anyone care to give an example of when sgn(0)==0 is more useful? I generally use it in situations where only a non-zero result is meaningful. e.g. player.x + sgn(player.dx) * player.w to get the point in front of a player.

P#17122 2015-11-28 06:53 ( Edited 2015-11-28 11:53)

A common example of sgn(0)==0 would be in collision. The standard grid raycast loop uses it, since you don't want to step if you're moving zero in x or y:

sx = sgn(dx) sy = sgn(dy)
gx = flr(x/scale) gy = flr(y/scale)
curt = 0
dxt = sx*scale/dx dyt = sy*scale/dy #full grid step in t, div by 0=max in lua?
nxt = sx == 0 and 2 or ((scale*gx+.5*scale*(sx+1)) - x) / dx #first x in t
nyt = sy == 0 and 2 or ((scale*gy+.5*scale*(sy+1)) - y) / dy #first y in t
while(curt < 1) do
    if(nxt < nyt) then curt=nxt gx+=sx nxt+=dxt
    else curt=nyt gy+=sy nyt+=dyt end
    #do something at grid position (gx,gy)
end

I can't really think of other places where sign(x) is used offhand, it's kind of a rare function. Also that code is from memory, so don't trust me on it. =)

P#17174 2015-11-29 06:45 ( Edited 2015-11-29 11:45)

There was a sign function?! D: And I've been rolling my own! Gah.

P#17177 2015-11-29 10:11 ( Edited 2015-11-29 15:11)

Hey! I poked you Zep on twitter about this without realizing it was already being discussed.

sgn(0) = 0 is definitely the more common one in my experience; Flashpunk uses it in its utility functions, as does the C# standard Math library. Since zero is signless (usually), it doesn't seem correct to me for it to return 1.

I was planning to use this recently for an input system, making use of the new input bitfield like so:

local keys = btn()
x += sgn(band(keys, 2)) - sgn(band(keys, 1))
y += sgn(band(keys, 8)) - sgn(band(keys, 4))

Versus how I usually do it:

if btn(0) then
    x -= 1
end
if btn(1) then
    x += 1
end
if btn(2) then
    y -= 1
end
if btn(3) then
    y += 1
end

I've just now tested it and apparently I'm not actually saving on tokens, haha. Maybe I don't want this feature after all ;)

P#18210 2016-01-09 12:20 ( Edited 2016-01-09 17:20)

In terms of saving tokens or writing elegant code, I think sgn(0)==0 vs. sgn(0) == 1 is much of a muchness. More important is that it behaves as you'd expect it to without reading the manual (when there is an entry!), and it seems most users expect sgn(0) == 0. I'll see about changing it to return 0 in 0.1.5 if there's a way to do it without breaking carts in the wild too much.

P#18225 2016-01-10 19:31 ( Edited 2016-01-11 00:31)
1

@jacobalbano @zep

I dug up this thread!

I would expect FALSE to return 0 to make more sense for use.

Cart #sgn_control-0 | 2023-04-25 | Code ▽ | Embed ▽ | No License
1

--** 32 tokens **--
if btn(0) then
 x -= 1
end
if btn(1) then
 x += 1
end
if btn(2) then
 y -= 1
end
if btn(3) then
 y += 1
end

--** 30 tokens **--
x += btn(0) and -1 or btn(1) and 1 or 0
y += btn(2) and -1 or btn(3) and 1 or 0

--** 26 tokens [use sgn()!] **--
x += sgn(btn(1)) - sgn(btn(0))
y += sgn(btn(3)) - sgn(btn(2))
--** Wrapper function with FALSE returning 0 **--

_sgn,sgn=sgn,function(v)
 return v == false and 0 or _sgn(v)
end
P#128984 2023-04-25 03:12 ( Edited 2023-04-25 08:02)
1

@shiftalow @zep

Interesting idea. Not sure if, mathematically, it makes sense for false to be negative. False is usually 0. Mind you, false is semantically synonymous with negative in spoken language, and 0 being "positive" is just an arbitrary choice in two's-complement notation.

Setting that quibble aside, if one wants to convert a boolean to 0/1 they can already do it with tonum(bool), so maybe letting sgn(bool) produce -1,+1 would be a good feature, since it provides the extra functionality your examples demonstrate, whereas the current functionality isn't really functionality at all.

P#129069 2023-04-27 04:28 ( Edited 2023-04-27 04:33)
1

In my initial post I was expecting 0 to be output to result in a sgn(false) suitable for btn().

However, I noticed in @Felice's reply the ability to numerically convert bool to 1,0 with tonum()!
I am now convinced that sgn(bool) outputs +1,-1.

We will be able to choose between tonum() which outputs 1,0 and sgn()` which outputs 1,-1! (*1 

Thanks!

(*1 Correction of text

Since I can choose between tonum(), which outputs 1 and 0, and sgn(), which outputs 1 and -1, I am now convinced that sgn(bool) outputs +1,-1!

P#129076 2023-04-27 08:20 ( Edited 2023-05-01 15:07)
1

@shiftalow

Ah! Right, I actually misread your code, so yes, all you needed was for tonum() to do what you were asking for sgn() to do.

This is all good to know, by the way! I only learned that tonum() handled booleans because of this thread. It's definitely a great way to handle dpad input.

Hm, I should update the wiki if it doesn't already mention this. Oh, it already does. Silly me. Didn't see it, though, since the note was buried in the long text. I edited it to be more clear.

P#129126 2023-04-29 09:43

[Please log in to post a comment]

Follow Lexaloffle:          
Generated 2024-03-28 09:03:03 | 0.030s | Q:37