2017-07-15 11 views
0

J'essaie d'enregistrer la sortie $result de proc Inverse2 qui est planifiée après chaque seconde (elle est appelée dans une autre procédure, cette procédure est replanifiée pendant 1s est pourquoi la procédure Inverse2) Je veux obtenir une sortie qui est {xy} maintenant et attribuer variable pour deux derniers casQuelle est la raison de l'erreur "Exception de virgule flottante (core core dumped)"

x1-> x location at current time (for example at 8.0) 
y1-> y location at current time 
x2-> x location at (current time+1) (for example at 9.0) 
y2-> y location at (current time+1) 

et utiliser pour d'autres calculs. Voici un code que j'ai essayé mais l'erreur que j'ai obtenue après deux itérations est Floating point exception (core dumped). Où je me trompe?

code:

set result {} 

proc Inverse2 {m} { 
    set op [open output.tr w] 
    global result 
    global ns 
    set now [$ns now] 
    lassign [lindex $m 0 2] x1 
    lassign [lindex $m 0 3] y1 
    lassign [lindex $m 0 6] d1 
    lassign [lindex $m 1 2] x2 
    lassign [lindex $m 1 3] y2 
    lassign [lindex $m 1 6] d2 
    lassign [lindex $m 2 2] x3 
    lassign [lindex $m 2 3] y3 
    lassign [lindex $m 2 6] d3 

    set mt {{? ?} {? ?}} 
    lset mt 0 0 [expr 2*($x1-$x2)] 
    lset mt 0 1 [expr 2*($y1-$y2)] 
    lset mt 1 0 [expr 2*($x1-$x3)] 
    lset mt 1 1 [expr 2*($y1-$y3)] 
    set const {{?} {?}} 
    lset const 0 [expr {(pow($x1,2)+pow($y1,2)-pow($d1,2))-(pow($x2,2)+pow($y2,2)-pow($d2,2))}] 
    lset const 1 [expr {(pow($x1,2)+pow($y1,2)-pow($d1,2))-(pow($x3,2)+pow($y3,2)-pow($d3,2))}] 
    #puts $result "$const" 
    # puts $result "$mt" 
    set x [expr {double([lindex [Inverse3 $mt] 0 0] * [lindex $const 0] 
         + [lindex [Inverse3 $mt] 0 1] * [lindex $const 1])}] 
    set y [expr {double([lindex [Inverse3 $mt] 1 0] * [lindex $const 0] 
         + [lindex [Inverse3 $mt] 1 1] * [lindex $const 1])}] 

    lappend result "$x $y $now" 
    puts $result 
    for {set i 0} {$i< [llength $result]} {incr i} { #for latest two instances 
     for {set j 1} {$i< [llength $result]} {incr j} {  
      set X1 [lindex $result $i 0] 
      set Y1 [lindex $result $i 1] 
      if {[llength $result] >1} { #to ensure length of list is greater than 1 
       set X2 [lindex $result $j 0] 
       set Y2 [lindex $result $j 1] 

       set v [expr hypot($X2-$X1,$Y2-$Y1)/ ($now-($now-1))] 
       set theta [expr acos(($X2-$X1)/(hypot($X2-$X1,$Y2-$Y1)))] 
       set Xp [expr ($X2+($v*$now*cos($theta)))] 
       set Yp [expr ($Y2+($v*$now*sin($theta)))] 
       puts "$Xp $Yp" 
      } 
      break 
     } 
    } 
} 

Répondre

1

exceptions à virgule flottante peuvent provenir de différentes choses. En général, le principal coupable est de faire quelque chose de terrible, comme diviser zéro par zéro. Cependant, Tcl est généralement assez bon pour s'assurer que de telles choses ne plantent pas complètement votre programme, et à la place génèrent juste des erreurs que vous pouvez attraper. Ce qui se passe est donc l'un des cas les plus délicats, ou en raison de l'exécution de ns2 et de l'activation des erreurs de virgule flottante (l'implémentation standard de Tcl les désactive précisément pour éviter les crashs fatals probablement injustifiés).

Si c'est le dernier, déplacer le traitement hors du processus dans un standard tclsh est la voie la plus facile. Nous pouvons faire des garanties plus fortes sur l'exactitude du comportement, car nous avons plus de contrôle sur les choses délicates comme les drapeaux FPU.

Mais si elle est l'ancienne ... le problème doit se situer dans ces lignes:

  set v [expr hypot($X2-$X1,$Y2-$Y1)/ ($now-($now-1))] 
      set theta [expr acos(($X2-$X1)/(hypot($X2-$X1,$Y2-$Y1)))] 
      set Xp [expr ($X2+($v*$now*cos($theta)))] 
      set Yp [expr ($Y2+($v*$now*sin($theta)))] 

Sur les lignes là, celui qui ressemble le plus suspect est le calcul de theta. Il y a plusieurs problèmes avec ce que vous faites (par exemple, il ne gérera pas correctement certains quadrants en raison des périodicités trigonométriques) mais le gros méchant, c'est que vous avez une division qui sera nulle si deux positions successives sont le même. Étant donné que vous êtes en mesure d'utiliser hypot(), le calcul de l'angle est de loin mieux calculé avec atan2(), car cela traite beaucoup mieux les cas de bords difficiles (par exemple, il n'a pas de problèmes avec des infinies horribles). Essayez ceci:

  set theta [expr { atan2($Y2-$Y1, $X2-$X1) }] 

également mettre vos expressions { accolades } comme je l'ai fait ci-dessus. Cela permet à Tcl de compiler bytecode l'expression et rend votre code un peu plus rapide. Il vous permet également de placer des espaces dans l'expression en toute sécurité, ce qui facilite considérablement la lisibilité même lorsque vous ne divisez pas plusieurs lignes, et vous assure (beaucoup!) De meilleurs messages d'erreur si jamais vous utilisez une variable valeur numérique dans votre expression. Bref, c'est facile à faire et améliore grandement votre code.


Autres problèmes mineurs

  1. Est-ce que vous attendez ($now-($now-1)) à calculer jamais autre chose que 1? Ou au moins une valeur très proche de 1.0, étant donné que vous traitez des nombres à virgule flottante pour le temps de simulation? Je pense que votre calcul de v peut être simplifié en toute sécurité jusqu'à l'utilisation directe de hypot().

  2. Ces deux boucles imbriquées regard étrange:

    for {set i 0} {$i< [llength $result]} {incr i} { 
        for {set j 1} {$i< [llength $result]} {incr j} {  
    

    Je pense que vous soit dire de faire ceci:

    for {set i 0} {$i< [llength $result]} {incr i} { 
        for {set j 0} {$j< [llength $result]} {incr j} {  
         if {$i == $j} continue; # Skip the diagonal in the comparison matrix 
    

    ou ceci:

    for {set i 0} {$i< [llength $result]} {incr i} { 
        for {set j [expr {$i + 1}]} {$j< [llength $result]} {incr j} { 
         # Just the upper triangle of the comparison matrix 
    

    selon que le reste du code devrait comparer les valeurs des deux côtés (mais jamais avec lui-même), ou simplement ré. Ce dernier fait moins de travail, mais pourrait être erroné si les comparaisons ne sont pas symétriques (ce qui dépend des détails de ce que vous faites).

+0

pour ce qui concerne loop.I souhaitez affecter la variable à la sortie par exemple 'result' de $ pour deux derniers tuple comme this.eg après deux itérations' $ result' ressembler à ceci {500,1 450 8,0} {478 378,1 9,0} donc je veux assigner x1> [lindex $ résultat 0 0] & y1> [lindex $ résultat 0 1] et x2> [lindex $ résultat 1 0] & y2> [lindex $ résultat 1 1] .Par conséquent j'ai initialisé "i" avec 0 et "j" avec 1 pour qu'après chaque itération il prenne les deux derniers tuples de la liste. 'if' à l'intérieur de la seconde boucle car la liste initiale n'a qu'un seul tuple donc la seconde pour la boucle ne peut pas assigner de variable et va renvoyer l'erreur. –