MantisBT  opensim  
View Issue Details  
ID  Project  Category  View Status  Date Submitted  Last Update 
0008311  opensim  [REGION] Script Functions  public  20180403 10:27  20180711 10:55 
Reporter  Kayaker Magic  
Assigned To  UbitUmarov  
Priority  low  Severity  minor  Reproducibility  always 
Status  resolved  Resolution  fixed  
Platform  Linux/Mono  OS  OpenSim 0.9.1.dev  OS Version  0.9.1 dev 
Product Version  master (dev code)  
Target Version  Fixed in Version  
Git Revision or version number  f83f7e18b6527ec4733d108898fee5539173cd99  
Run Mode  Grid (Multiple Regions per Sim)  
Physics Engine  ODE  
Environment  Mono / Linux64  
Mono Version  trunk  
Viewer  FireStorm  
Summary  0008311: llAcos and llAsin return NaN for values very close to 1.0  
Description  I've been seeing a very rare error where llAcos returns a bad value that turns out to be NaN. This is the value it returns when you give it an input value that is out of bounds. But this was happening to me while using llAcos to calculate the angle between two unit vectors, a situation that was never supposed to be out of bounds. Floating point numbers, even doubles, have a finite resolution. If you generated unit vectors at all possible angles, each component of the vector would be truncated by a different amount. The result is that some of the unit vectors will be slightly longer than 1.0 (about 2% of them), some less than 1.0 (about 34%) and most actually would have a length that was the floating point representation of 1.0 (about 62%, based on random samples). In a small number of innocent calculations, the truncation error will result in unit vectors that are slightly longer than one and the dot product calculated will be slightly greater than one. This is an invalid value for cosine and if you call llAcos to find the angle, the result will be NaN. A similar function in the same source fie, llAngleBetween, tests for >1.0 and assumes an angle of 0.0 in that case. This isn't the best solution for llAcos because you do want to detect truly invalid values. So I propose testing in llAcos for a small range of values between 1.0 and 1.0000001, forgiving those invalid values and substituting an angle of 0.0. The truncation errors in singleprecision vector lengths should always be less than 0.0000001. The same thing should be done with llAsin, although it will substitute +/PI_BY_TWO. llAtan has no range limit and does not have this problem.  
Steps To Reproduce  The following script gets NaN errors caused by floating point truncation of unit vectors. After applying the following patch, the errors are gone. //The dot product of a unit vector with itself should always be 1.0 // never >1.0 integer times=0; integer fails=0; default { state_entry() { llSetTimerEvent(0.2); } timer() { times += 1; //generate a random unit vector vector a=llVecNorm(< llFrand(2.0)1.0, llFrand(2.0)1.0, llFrand(2.0)1.0>); vector b=a; float cos=a*b; //the dot product of two vectors is the cosine of the angle between them float angle = llAcos(cos); if (angle!=angle) //this will be true if angle==NaN, according to IEEE { //why would llAcos return NaN? Because cos>1.000000000 fails += 1; llOwnerSay("NaN! vector="+(string)a+ " failed "+(string)fails+" of "+(string)times+", "+(string)((integer)(100.0*(float)fails/(float)times))+"%"); } llSetText((string)times,<0,1,0>,1.0); } }  
Additional Information  From 356225736b2418b797fb71328f84288c98a233c2 Mon Sep 17 00:00:00 2001 From: Mike Higgins <mike@kayaker.net> Date: Tue, 3 Apr 2018 09:47:55 0700 Subject: [PATCH] put a test in llAcos and llAsin to prevent NaN on values slightly above 1.0  .../Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs  11 ++++++++++ 1 file changed, 10 insertions(+), 1 deletion() diff git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index bac1468..47c2355 100644  a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ 860,6 +860,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Vector llVecNorm(LSL_Vector v) { +//Console.WriteLine("Called llVecNorm ============================================="); m_host.AddScriptLPS(1); return LSL_Vector.Norm(v); } @@ 5571,12 +5572,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Float llAcos(double val) { m_host.AddScriptLPS(1);  return (double)Math.Acos(val); + const double TRIG_THRESHOLD = 0.0000001f; //Kayaker: truncation errors can result in values slightly above 1.0 + if (Math.Abs(val) > 1f && (Math.Abs(val)1f)<TRIG_THRESHOLD) //llAcos should forgive this and + return (double)0.0; //return 0 degrees as if this was +/1.0 + return (double)Math.Acos(val); //else return the normal value } public LSL_Float llAsin(double val) { m_host.AddScriptLPS(1); + const double TRIG_THRESHOLD = 0.0000001f; //Kayaker: truncation errors can result in values slighty above 1.0 + if (val > 1f && (val1f)<TRIG_THRESHOLD) //llAsin should forgive this and + return (double)ScriptBaseClass.PI_BY_TWO; //return pi/2 as if this was 1.0 + if (val < 1f && (val1f)<TRIG_THRESHOLD) + return (double)ScriptBaseClass.PI_BY_TWO; //or pi/2 if this was 1.0 return (double)Math.Asin(val); }  2.7.4  
Tags  No tags attached.  
Relationships  
Attached Files  
Issue History  
Date Modified  Username  Field  Change  
20180403 10:27  Kayaker Magic  New Issue  
20180403 10:43  melanie  Note Added: 0032627  
20180403 11:05  UbitUmarov  Note Added: 0032628  
20180403 15:20  UbitUmarov  Note Added: 0032629  
20180403 17:23  UbitUmarov  Note Added: 0032630  
20180711 10:55  UbitUmarov  Note Added: 0032780  
20180711 10:55  UbitUmarov  Status  new => resolved  
20180711 10:55  UbitUmarov  Resolution  open => fixed  
20180711 10:55  UbitUmarov  Assigned To  => UbitUmarov 
Notes  























