PDA

Voir la version complète : [PROG] VB.net, C# .Net, Saucisses.Net, toute la prog made in Microsoft



deathdigger
06/10/2010, 15h47
Bonjour,

J'ai pas trouvé de topic pour la programmation (alors que vu le nombre de geek ici, il faudrait faire un sous-forum :p), donc je me permet de créer un sujet.

J'aimerais faire un chrono en VB, un vrai chrono avec affichage des centièmes et dixièmes de secondes, je connais déjà le principe du timer, j'ai bien tout mis en place avec une intervalle de 10 (10 millisecondes = 1 centième de seconde si je ne m'abuse), j'ai fait mes conversions afin que ça s'affiche en mm:ss:ff ce qui donne ça :


Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
milisec = milisec + 1
If milisec = 99 Then
milisec = 0
sec = sec + 1
End If
If sec = 60 Then
sec = 0
min = min + 1
End If
chrono.Text = min.ToString("00") & ":" & sec.ToString("00") & ":" & milisec.ToString("00")



Ça me semble correct, sauf que en comparant avec un chronomètre à la main, j'obtiens des différences flagrantes (jusqu'à 5 secondes de différence au bout de 10 secondes).

Alors 2 possibilités :
- Je suis con et j'ai mal fait ma conversion millisecondes->secondes
- VB est limité et la gestion du temps est fausse.

En cherchant par rapport à la deuxième possibilité, j'ai cru comprendre qu'en dessous de 20ms, le timer n'est pas précis (alors qu'il permet d'être avec un intervalle de 1 millisecondes, va comprendre :tired:). Par contre pour résoudre simplement ce soucis, je n'ai pas trouvé de trucs, quelqu'un aurait déjà rencontré ce soucis ?

superlag
06/10/2010, 19h31
C'est pas la vitesse d'exécution du langage qui serait en cause?

deathdigger
06/10/2010, 21h59
C'est pas la vitesse d'exécution du langage qui serait en cause?

Yep il me semble, d'autant plus que je fais afficher le résultat :(

Selon ce que j'ai lu, faut passer par un time now - time du début, mais dans ce cas, pas d'affichage à la volée (en soi, c'est pas trop grave mais c'est plus classe avec), sinon y'a ceux qui passent par l'horloge du proc', mais en fait ça dépend de la puissance de la machine, le gros bordel quoi :tired:
C'est tout de même étonnant qu'ils proposent un intervalle jusqu'à 1 milliseconde alors qu'il est impossible de l'utiliser...

Møgluglu
06/10/2010, 22h30
Laisse-moi deviner, c'est toi le programmeur qui t'occupes des systèmes de guidage des missiles américains?

http://www.gao.gov/products/IMTEC-92-26

Ça ne peut pas marcher comme ça. Déjà, c'est pas parce que tu peux mettre des délais à la milliseconde près que c'est précis à la milliseconde.
Même si c'était « précis à la milliseconde près », ça voudrait dire que quand tu demandes 1ms tu obtiens quelque chose entre 0,5ms et 1,5ms.

Ensuite, les évènements en VB ne sont pas précis. Tu peux très bien ne rien avoir pendant 50ms, puis recevoir en rafale 33 évènements dans la milliseconde suivante, avec 17 qui se sont perdus en route.

Ce qu'il faut, c'est récupérer la valeur d'une des nombreuses horloges systèmes, et la convertir dans le format que tu veux. L'évènement Timer ne s'occupe que de l'affichage, pas du calcul.
En passant, ton écran n'affiche qu'une image toutes les 17ms, ça ne sert à rien de rafraîchir l'affichage plus souvent.
(ou disons 8ms pour respecter Shannon-Nyquist)

Foudge
06/10/2010, 22h48
deathdigger> Non seulement ce n'est pas précis à la ms près, mais dans ton cas, c'est surtout que tu ne peut pas descendre sous les 15ms. C'est donc pour ça que tu te retrouves à 15s pour 10s réel.
Passe à 20ms et tu te retrouveras magiquement à 10s affiché = 10s réel, mais ton chrono ne sera précis qu'à 0.02s, au mieux !

Ceci dit, il existe une solution à ce problème que j'ai également rencontré en C++ et résolu via l'utilisation de timeBeginPeriod qui permet de régler le "Minimum timer resolution" :
http://msdn.microsoft.com/en-us/library/dd757624%28VS.85%29.aspx

En VB et VB.Net, semble y avoir une solution également :
http://gpwiki.org/index.php/VB:Timers

deathdigger
06/10/2010, 22h53
Laisse-moi deviner, c'est toi le programmeur qui t'occupes des systèmes de guidage des missiles américains?

http://www.gao.gov/products/IMTEC-92-26

Ça ne peut pas marcher comme ça. Déjà, c'est pas parce que tu peux mettre des délais à la milliseconde près que c'est précis à la milliseconde.
Même si c'était « précis à la milliseconde près », ça voudrait dire que quand tu demandes 1ms tu obtiens quelque chose entre 0,5ms et 1,5ms.

Ensuite, les évènements en VB ne sont pas précis. Tu peux très bien ne rien avoir pendant 50ms, puis recevoir en rafale 33 évènements dans la milliseconde suivante, avec 17 qui se sont perdus en route.

Ce qu'il faut, c'est récupérer la valeur d'une des nombreuses horloges systèmes, et la convertir dans le format que tu veux. L'évènement Timer ne s'occupe que de l'affichage, pas du calcul.
En passant, ton écran n'affiche qu'une image toutes les 17ms, ça ne sert à rien de rafraîchir l'affichage plus souvent.
(ou disons 8ms pour respecter Shannon-Nyquist)

Ca vaut pas la confusion entre mètres et pieds à la NASA ^_^
Je ne comprends pas qu'un programme tournant sur un PC moyen/puissant ne puisse atteindre la qualité d'un bête chronomètre à 2€... Et ce qui me choque, c'est que l'écart devient vite énorme (5 secondes d'écart au bout de 15 secondes de chrono !)

Par rapport à ton conseil, j'en étais arrivé à la même conclusion en tombant sur cette page :
http://faq.vb.free.fr/index.php?question=176

Je crois que je vais me baser sur GetTickCount au final, 16 millisecondes c'est pas trop mal comme précision.

EDIT : A Foudge, ouais c'est un peu ce que je compte faire ;)

Question bête, c'est spécifique à VB cette limitation ou tous les langages ont ce problème ?

Møgluglu
06/10/2010, 23h55
Question bête, c'est spécifique à VB cette limitation ou tous les langages ont ce problème ?

Non, c'est comme ça dans tous les langages et sur tous les OS, c'est lié au hardware.

Les sources de temps sur un PC sont :
- l'horloge RTC (http://en.wikipedia.org/wiki/Real-time_clock), celle qui tourne avec la pile quand le PC est débranché... Relativement stable dans le temps, mais résolution merdique : dans les 15 ms (65536 Hz),
- le PIT (8253) (http://en.wikipedia.org/wiki/8253) qui a une résolution d'environ 1193181,8181Hz d'après Wiki, soit ~838µs,
- le HPET (http://en.wikipedia.org/wiki/HPET) qui tend à remplacer le 8253, résolution dans les 10ns,
- le TSC (http://en.wikipedia.org/wiki/Time_Stamp_Counter), qui fait semblant de tourner à la fréquence du CPU mais en fait tourne plutôt à celle du FSB ou base clock,
- le compteur de CPU_CLK_UNHALTED du CPU, qui compte les vrais cycles...

Sous Windows, timeGetTime utilise le RTC. QueryPerformanceCounter utilisait le 8253 de mon temps, mais il semble qu'il se base sur le TSC maintenant (au grand dam de ceux qui utilisaient le TSC pour compter des cycles :().

deathdigger
12/10/2010, 20h17
Je solutionne pour ceux qui seraient intéressés :


Public Class Form1
Private Declare Function timeGetTime Lib "winmm.dll" () As Integer
Private Declare Function timeBeginPeriod Lib "winmm.dll" (ByVal uPeriod As Integer) As Integer
Private Declare Function timeEndPeriod Lib "winmm.dll" (ByVal uPeriod As Integer) As Integer
Dim debut As Long
Dim fin As Long
Dim resultat As Long
Dim sec As Integer
Dim min As Integer
Dim cent As Integer

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
debut = timeGetTime()
End Sub

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
fin = timeGetTime()
resultat = fin - debut
sec = resultat \ 1000
cent = resultat Mod 1000
min = sec \ 60
sec = sec Mod 60
TextBox1.Text = min.ToString("00") & ":" & sec.ToString("00") & ":" & cent.ToString("000")
End Sub
End Class

Donc il faut faire appel aux DLL pour la gestion du temps, et après, c'est d'une simplicité enfantine :wub:
Comparé avec un vrai chronomètre, la différence est de quelques centièmes, donc c'est nickel (ça doit s'expliquer par le fait qu'il faut appuyer sur le bouton du chrono + le bouton du script en même temps, sans compter la légère latence de la souris, etc...).

Je modifie le titre du sujet pour ceux qui auraient d'autres questions :)

deathdigger
14/06/2011, 11h25
Gnuuuuup !

Je up ce topic pour une question cette fois en C#.

J'essaie désesperement de deserialiser une liste d'objets d'un fichier XML.
Alors quand j'essaie de déserialiser un objet unique pas de soucis, mais pour une liste d'objets, ça se complique :

D'abord ce qui marche :
Mon XML


<?xml version="1.0" encoding="utf-8" ?>
<Destinataire id="1">
<adresse>Toto</adresse>
</Destinataire>


Ma classe


public class Destinataire
{
[XmlAttribute("id")]
public int id {get;set;}
public string adresse {get;set;}

public Destinataire()
{

}
}


Mon void


XmlSerializer ser = new XmlSerializer(typeof(Destinataire));
FileStream fichier = new FileStream("agences.xml", FileMode.Open);
List<Destinataire> liste_dest = new List<Destinataire>();
Destinataire dest1 = new Destinataire();
dest1 = (Destinataire)ser.Deserialize(fichier);
Destinataire dest2 = new Destinataire();
dest2.id = 2;
dest2.adresse = "Tutu";
liste_dest.Add(dest1);
liste_dest.Add(dest2);
textBox1.Text = dest1.id.ToString() + " " + dest1.adresse + " " + liste_dest.Count.ToString();
dataGrid_AffDest.DataSource = liste_dest;

(c'est juste à des fins de test)

Maintenant, si je rajoute cette classe


public class Liste_Destinataires
{

public List<Destinataire> liste_destinataires {get;set;}

public Liste_Destinataires()
{
}

}


Et que mon XML ressemble à ça :


<?xml version="1.0" encoding="utf-8" ?>
<Liste_Destinataires>
<Destinataire id="1">
<adresse>Toto</adresse>
</Destinataire>
<Destinataire id="2">
<adresse>Blabla</adresse>
</Liste_Destinataires>


Et enfin mon code


XmlSerializer ser = new XmlSerializer(typeof(Liste_Destinataires));
FileStream fichier = new FileStream("agences.xml", FileMode.Open);
Liste_Destinataires list_dest = new Liste_Destinataires();
list_dest = (Liste_Destinataires)ser.Deserialize(fichier);
dataGrid_AffDest.DataSource = list_dest.liste_destinataires;
textBox1.Text = list_dest.liste_destinataires.Count.ToString();


Il n'y a pas de Destinataires dans ma liste (list_dest), j'ai l'impression qu'ils ne se sont pas instanciés.
Quelqu'un est à l'aise avec C# pour m'expliquer où j'ai merdé ? (j'ai lu une bonne trentaine de réponses sur la msdn et d'autres sites, mais sans explication, c'est un peu difficile).


EDIT : Solution trouvée !
En fait, le code est bon, ce qui ne l'était pas, c'était le fichier XML !
Pour trouver la solution, j'ai géneré un fichier via serialize pour voir la structure qu'il prenait, ça donne ça :


<?xml version="1.0"?>
<Liste_Destinataires xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<liste_destinataires>
<Destinataire id="1">
<adresse>Caca</adresse>
</Destinataire>
<Destinataire id="2">
<adresse>CICI</adresse>
</Destinataire>
<Destinataire id="3">
<adresse>Coucou</adresse>
</Destinataire>

</liste_destinataires>
</Liste_Destinataires>

Voilà, deux jours de prise de têtes pour un simple problème de XML :sad:

elpaulo
14/06/2011, 23h25
A savoir que le mieux reste de faire un schéma XSD pour ton XML, ce qui te permet, en plus d'avoir des règles bien définies pour la structure de ton XML, de générer les classes correspondantes avec l'outil xsd.exe fourni avec Visual Studio. Et puis ca permet de valider le XML en entrée avant de s'en servir, ce qui ne mange pas de pain non plus.

deathdigger
23/06/2011, 20h14
Jamais testé, mais effectivement, ça peut être pas mal :)