forums

TNT Basic Forums > Bugs!
Cos() and Sin() commands acting up...
< Last Thread     Next Thread >
Author
Thread        Post A Reply

12-09-2006 05:41

Posted by:
Farmer

Location:
Somewhere in space...

Find more posts by Farmer

This is definitely a weirdish problem. I'm not sure whether I'm imagining things am actually wrong or if others are having this problem, but I figure that the forums are an excellent place to find out. I'm having difficulty with the values that the sin/cos commands are returning. My simplified code looks like this:

quote:
print "Cos:"
print cos(0)
print cos(90)
print cos(180)
print cos(270)
print ""
print "Sin:"
print sin(0)
print sin(90)
print sin(180)
print sin(270)


The output is very, very, uncannily similar to this ;) :
quote:
Cos:
1
-4.37114e-08
-1
1.19249e-08

Sin:
0
1
-8.74228e-08
-1


Now, I may have checked this insufficiently, but the Mac calculator said that cos(90)=0 and sin(180)=0. Wait, I'm not sure again! I'll go check...

... yep, that's what they should be. So... I wonder why this weird number shows up in scientific notation and everything. Is there something wrong with my computer, or TNT? This is important to a game I'm making, and I've never had this problems before.

Just because I thought you'd ask:
Mac OS 10.4.8
iMac PPC G5
TNT Basic 1.31


Thanks a bundle!

12-09-2006 14:14

Posted by:
allnodcoms

Location:
hertfordshire (England)

Click Here to Email allnodcoms   Find more posts by allnodcoms

No, everything's good...

Everything is doing roughly what it should. The reason you're getting some strange results is because you're asking it to do some strange math. Take a look at the following graphic and you should see what I mean...



The values for sin, cos and tan are cyclic, they repeat themselves for various values (as shown above). Calculator is giving you float point values as the return, and TNT is giving you exponentials.

When I've done 3D in TNT I use a look-up table, calculate cos(1) and sin(1) then build an array to hold multiples of these base values. It's a lot quicker as well... There's an example of this in the directory if you want to have a look. Click here to go to the relevant page. It's the 3D Cube example...

Hope this sets your mind at ease, and happy coding...

Danny (nods)

12-09-2006 15:16

Posted by:
allnodcoms

Location:
hertfordshire (England)

Click Here to Email allnodcoms   Find more posts by allnodcoms

Do what? Did any of that make sense?

Can't believe I posted that... I've read it back and even I'm confused!

Anyway, what I was trying to say (obviously before a coffee and a cigarette) is that everything is OK, TNT is simply returning the result with greater precision than Calculator.

The "strange math" bit was misleading, basically math functions aren't normally used through the full 360 degrees. 3D programming is generally done in 90 degree steps (quadrants) or 45 degree steps (octants) and then flipped round or over, because of the 'look-up' method I mentioned above. There's nothing wrong with using all the angles of course, you're just holding more data than you need as the values repeat themselves in a logical pattern.

OK, re-read that and this post makes more sense...

Danny (nods)

12-09-2006 17:06

Posted by:
Farmer

Location:
Somewhere in space...

Find more posts by Farmer

Thank you.

Whew. Good to know that's normal. I can now rest in peace.

Clarification: If I store one of the above sin or cos values in an int, will it round to 0 or to something else comepletely that will mess up my code? My code looks something like this (where, in this case, dir=90):

quote:
Move Sprite sin(dir)*50,-cos(dir)*50,10
Should it be:
quote:
int xd = sin(dir), yd = cos(dir)
Move Sprite xd*50,yd*50,10
?
Would this help eliminate "slightly off" movement; for example, moving the sprite one to the right and 50 up, which would be no good at all.

Thank you for your help.

12-09-2006 17:29

Posted by:
someone

Location:
Quebec ( Canada )

Click Here to Email someone   Find more posts by someone

You don't want to round sin and cos into int.

Don't do that:


int xd = sin(dir), yd = cos(dir)
Move Sprite xd*50,yd*50,10


Do that:


Move Sprite sin(dir)*50, cos(dir)*50,10

12-09-2006 17:31

Posted by:
someone

Location:
Quebec ( Canada )

Click Here to Email someone   Find more posts by someone

rounding into int would make things much worse. it could remove any rotation effect

12-09-2006 17:32

Posted by:
someone

Location:
Quebec ( Canada )

Click Here to Email someone   Find more posts by someone

"Would this help eliminate "slightly off" movement; for example, moving the sprite one to the right and 50 up, which would be no good at all.
"

if you want better precision, the only way i see is to stop using moan, and to store the position of the sprite in a float.

12-09-2006 17:46

Posted by:
Farmer

Location:
Somewhere in space...

Find more posts by Farmer

Multiples of 90

The only values I'm puting into the sin/cos functions are multiples of 90, as in the code above (0,90,180,270). Does this change your answer at all, since you know I should only get values of -1, 0, or 1 as outputs?

Curious. Thanks alot.

12-09-2006 19:27

Posted by:
allnodcoms

Location:
hertfordshire (England)

Click Here to Email allnodcoms   Find more posts by allnodcoms

Don't use sin() and cos()...

Use an array of ints with the values preloaded, then use something like mySin[dir] and myCos[dir]

As a quick note, you can store cos and sin results in an int, but you need to multiply by something pretty big (32,768 is a good one) and then use the result divided by the same amount (32,768 allows you to bit shift by 15, which is faster than the division).

Danny (nods)

12-09-2006 19:36

Posted by:
someone

Location:
Quebec ( Canada )

Click Here to Email someone   Find more posts by someone

if you don't plan on using other angles than multiples of 90, you don't need sin and cos at all... they'll just slow down things

12-09-2006 19:39

Posted by:
allnodcoms

Location:
hertfordshire (England)

Click Here to Email allnodcoms   Find more posts by allnodcoms

Another point (after re-reading the post)

Don't store sprite positions in a float, I've seen this a lot but it's really not necessary... There are far easier ways to accurately control the position. I don't know how you're controlling the sprites, but take a look at this example, it might help you out with placement and movement.

(I'll take a look at your map problem as well...)

Danny (nods)

12-09-2006 19:47

Posted by:
someone

Location:
Quebec ( Canada )

Click Here to Email someone   Find more posts by someone

true storing in a float is not necessary...

i wanted to point out it was the only possible way to be even more accurate, but forgot to mention it was useless

12-11-2006 06:26

Posted by:
Farmer

Location:
Somewhere in space...

Find more posts by Farmer

This should probably move...

quote:
(I'll take a look at your map problem as well...)
Thanks.
quote:
if you don't plan on using other angles than multiples of 90, you don't need sin and cos at all... they'll just slow down things
If I didn't use cos/sin values in the code, what would I use? I don't like using them; I simply did it out of neccesity. Is there another option?

The code is supposed to move the sprite up, down, left, or right depending on the angle given: 0 is straight up, 90 is straight right, 180 is straight down, and 270 is straight left, similar to the angles used in "Calculate Angle." Using cos/sin(s) was supposed to change this:
quote:
if dir=0
Move Sprite 1,0,-50,5
else if dir=90
Move Sprite 1,50,0,5
else if dir=180
Move Sprite 1,0,50,5
else if dir=270
Move Sprite 1,-50,0,5
end if
... to this:
quote:
Move Sprite 1, sin(dir), -cos(dir), 5
I assumed that the second code block was faster, and it is certainly more compact. Is there another way to do this? I don't want to bother anyone, and my questions should probably be moved to another forum, but I'm too lazy. My deepest apologies.

Thank you all. You've made me smarter. :)

12-11-2006 06:34

Posted by:
appleide

Click Here to Email appleide   Find more posts by appleide

more compact code:
Not sure if its faster though; should be rather fast.
int i
for i=0 to 3
if dir=i*90
move sprite,(-1)^(i+1)*50,-((-1)^(i+1))*50,5
end if
next

12-11-2006 06:38

Posted by:
appleide

Click Here to Email appleide   Find more posts by appleide

Faster version:

int i
for i=0 to 3
if dir=i*90
move sprite 1,(-1)^(i+1)*50,-((-1)^(i+1))*50,5
break
end if
next

12-11-2006 07:32

Posted by:
allnodcoms

Location:
hertfordshire (England)

Click Here to Email allnodcoms   Find more posts by allnodcoms

Take a look back at my earlier post...

There is a much, much faster way....

quote:
Use an array of ints with the values preloaded, then use something like mySin[dir] and myCos[dir]

Also, if you always multiply by the same amount (50), do the multiplication when you pre-load the array. This way you are getting rid of the sin() and cos() functions and two multiplications. If you are only ever going to use multiples of 90 degrees then just load either -50, 50 or 0 into the appropriate array element and away you go...

Danny (nods)

12-11-2006 10:06

Posted by:
appleide

Click Here to Email appleide   Find more posts by appleide


You mean 'preload' like this?
int mySin[360],myCos[360]
mySin[0]=0
mySin[90]=50
mySin[180]=0
mySin[270]=-50
myCos[0]=50
myCos[90]=0
myCos[180]=-50
myCos[270]=0

Wouldn't it use a lot of memory, with 720 array values?

12-11-2006 10:10

Posted by:
appleide

Click Here to Email appleide   Find more posts by appleide

Wow... That's neat, if you actually got 360 possible angles... you can just throw sin and cos away.

12-11-2006 13:39

Posted by:
allnodcoms

Location:
hertfordshire (England)

Click Here to Email allnodcoms   Find more posts by allnodcoms

That's about it...

I kind of meant that the directions be normalized a bit though... When you load up the direction value, don't use angles. I assume (as you're using orthogonal angles) that you are controlling with the keyboard, so the fastest way is say that the direction=scan code-122 (if scan code>122 and <127). This gives left=1, right=2, down=3 and up=4. It's much faster than four separate tests as well. If you leave myCos[0]=0 and mySin[0]=0 you don't even need to test for direction changes, if no keys are pressed then direction=0 and the offsets will also be zero, you drop another test from the loop and squeeze a few more clock cycles out of it!

Hope this helps...

Danny (nods)

12-12-2006 04:51

Posted by:
Farmer

Location:
Somewhere in space...

Find more posts by Farmer

Good advice!

I shall implement this new technique immediately. As soon as I have time. ;)

Thank you all.

All times are GMT        Post A Reply

Forum Jump:
< Last Thread     Next Thread >

< Contact Us - TNT Basic >

Powered by: vBulletin Lite Version 1.0.1 Lite
Copyright © Jelsoft Enterprises Limited 2000.