Calcul d'amateur cherche une façon plus professionnelle!

Pedro51

Member
Salut, j'ai besoin de calculer plusieurs données dont pour cet exemple les Wattsheures par kilomètre parcouru, ce qui permet par la suite de connaitre l'autonomie du véhicule. Un peu comme sur les voitures, la consommation instantanée par l/100km. les autres calculs étant similaires, Je vous propose que l'on s'attarde sur celui ci.

Voici donc un programme test du calcul:
Code:
symbol units        =b6
symbol tens         =b7
symbol hundreds     =b8
symbol thousands    =b9
symbol tenthousands =b10

main:		
		w0= 10				 
		w1= 1				
		gosub calcul
		
		w0= 100				 
		w1=12			
		gosub calcul
		
		w0= 150				 
		w1=25				
		gosub calcul
		
		w0= 190				 
		w1=100				
		gosub calcul
		
		w0= 488				 
		w1=35				
		gosub calcul
		
		w0= 488				 
		w1=50			
		gosub calcul
		
		w0= 9760				 
		w1=700				
		gosub calcul
		
		w0= 12200				 
		w1=875				
		gosub calcul
		
		w0= 9760				 
		w1=1000				
		gosub calcul
		
		w0= 12200				 
		w1=1250				
		gosub calcul
		
		w0= 17170				 
		w1= 3552				
		gosub calcul
		
		w0= 48800				 
		w1= 3500				
		gosub calcul
		
		do : loop while pinC.1=0		

calcul:	'produit en croix de wh(w1)*rapport(488)/nb de tours de roues effectué(w0)
		'rapport = 1000/205: 1000 correspond a 1km et 205 la circonference de la roues
		if w1 <= 130 then
		w2=w1*488
		w2=w2/w0
		else
		bintoascii w1,tenthousands,thousands,hundreds,tens,units
		units=units-48*488/100	
		tens=tens-48*488/10
		w2=hundreds-48*488
		w4=thousands-48*4880
		w2=units+tens+w2+w4
		w3=w0/100
		w2=w2/w3				
		endif
		
		sertxd (#w1," x 488 / ",#w0," = ",#w2,"wh/km")
		
		return
Donc un peu d'explications, vous avez surement compris que le "main:" sert juste a gaver les variables.

Les résultats sont assez proche a 1 prêt dans la mesure où les variables sont cohérentes.
C'est a dire que si vous roulez 1km, peu de chance que vous ayez consommé la totalité de la batterie (soit 888wh).
J'estime une fourchette de 25wh/km en utilisation normal voir 100wh/km max en poussant un peu.

w0 correspond au nb de tour de roues. w1 au nb de wh déjà consommé.
Ensuite, j'ai poussé les chiffres pour voir ce que cela donne.

La question: Comment rendre mes calculs plus "esthetique" j'ai envie de dire. Car bon, j'ai cherché a comprendre pendant plusieurs semaines les calculs en 32bits (pas H-24 non plus :eek: , je dort de temps en temps) et je doit dire que même si je comprend vaguement les exemples des autres, je n'arrive pas a appliquer sur mes propres calculs.
 

dje8269

Senior Member
Pour le prog ... . Je suis pas à la maison donc je n'ai pas pu regarder. Je le soupçonne d'aimer les maths
 

PieM

Senior Member
Comme il n'y a qu'un calcul à faire, une routine de calcul sur 32 bits, la seule capable de faire la division ne serait pas particulièrement adaptée !
Personnellement, je ne vois pas plus simple et plus "esthétique" que ce que vous avez fait.
 

Pedro51

Member
Oui, en fait je croit que je tourne un peu en rond avec çà. En fait la multiplication en 32bit ne pose pas de problème, c'est la division qui est plus délicate.
 

BESQUEUT

Senior Member
Je propose ça :
Code:
calcul:     'produit en croix de wh(w1)*rapport(488)/nb de tours de roues effectu?(w0)
		'rapport = 1000/205: 1000 correspond a 1km et 205 la circonference de la roues
		if w1 <= 130 then
			w2=w1*488
			w2=w2/w0


' JYB : ça peut aussi s'écrire plus simplement :
                       w2=w1*488/w0
		else
			bintoascii w1,tenthousands,thousands,hundreds,tens,units
			units=units-48*488/100  
			tens=tens-48*488/10
			w2=hundreds-48*488
			w4=thousands-48*4880
			w2=units+tens+w2+w4
			w3=w0/100
			w2=w2/w3 
	
	' methode JYB
			w3=w0/32
			w5=w3/2                                         ' calcul de l'arrondi : on ajoute 0,5 au résultat
			w4=w1*16**62464+w5/w3	             ' 488*128=62464		
		endif
		
		sertxd (#w1," x 488 / ",#w0," = ",#w2,"wh/km ",#w4,13)
		
		return
Ce n'est pas top (je ne suis pas très content du calcul de l'arrondi), mais déjà ça évite le bintoascii, et c'est en principe 3 fois plus précis puisque w0 est divisé par 32 au lieu de 100.

NB :
En simulation, j'obtiens ça :
875 x 488 / 12200 = 32wh/km 35

Je ne comprends pas pourquoi votre calcul donne 32 ?
 
Last edited:

Pedro51

Member
Salut,

Je viens de tester et cela fonctionne bien mieux. En tout cas
.
J'ai pas tout compris au premier abord mais je m'y plonge de suite pour ne pas rester ignorant.

Pour l'erreur de calcul de ma version, je sait d’où cela vient:


En réel:
units=units-48*488/100 = 24,4
tens=tens-48*488/10 = 341,6
w2=hundreds-48*488 = 3904
w4=thousands-48*4880 = 0
w2=units+tens+w2+w4 = 4270
w3=w0/100 = 122
w2=w2/w3 = 35

Dans le Picaxe:
units=units-48*488/100 = 24
tens=tens-48*488/10 = 85 ' l'erreur est ici puisque résultat supérieur a 255
w2=hundreds-48*488 = 3904
w4=thousands-48*4880 = 0
w2=units+tens+w2+w4 = 4013
w3=w0/100 = 122
w2=w2/w3 = 32
 

BESQUEUT

Senior Member
Pour l'erreur de calcul de ma version, je sait d&#8217;où cela vient:
Bon dieu mais c'est bien sur... (Cf commissaire B...)

Je croyais travailler sur des Words et il y un symbole déclaré en octet...


Petite explication sur la multiplication 64 bits :
Le résultat est divisé par 65536.
Donc, il faut se débrouiller pour multiplier le calcul par 65536.
On en profite pour mettre à l'échelle les facteurs pour qu'ils soient les plus grands possibles, ceci de façon à conserver un maximum de précision.

En l'occurence : 32*16*128=65536
 

BESQUEUT

Senior Member
Même tout déclaré en word le calcul donne ...34 au lieu de 35 ! :(
Oui, mais ça c'est normal : (j'obtiens la même chose avec Excel)
- les calculs pour les dizaines et les unités sont arrondis à l'entier inférieur.
- c'est pour ça que j'ajoute 0,5 pour faire l'arrondi habituel au dessus quand on dépasse .5

Dans le programme de Pedro, il faudrait écrire :
units=units-48*488+50/100
tens=tens-48*488+5/10

Les valeurs tests prises par notre ami Pedro sont souvent des cas particuliers pour lesquels le résultat exact est un nombre entier.
Si on prends 874 au lieu de 875, on voit bien que le résultat est fractionnaire, et que l'arrondi est "trop court"...
 
Last edited:

Pedro51

Member
Les valeurs tests prises par notre ami Pedro sont souvent des cas particuliers pour lesquels le résultat exact est un nombre entier.
Ah bah çà alors! j'ai prit des chiffres au hasard, et il tombe tous assez juste c'est vrai.
Bon j'ai compris le principe mais je ne l'aurais pas trouvé tout seul et encore moins l'expliquer à quelqu'un. Moi et le binaire, j'ai toujours eu du mal. Déjà avec l&#8217;électronique de logique c'était la cata!

Je vais essayer d'appliquer a mes autres calculs. Ouille j'ai déjà mal a la tête! ;)

Edit:
Ah bah çà alors! j'ai prit des chiffres au hasard, et il tombe tous assez juste c'est vrai.
M***e, j'utilise la calculette prog de win7, les résultats tombe toujours juste c'est sûr!
 
Last edited:

BESQUEUT

Senior Member
j'utilise la calculette prog de win7, les résultats tombent toujours justes c'est sûr!
Les systèmes d'exploitation comme Windows utilisent une représentation binaire des nombres.
La codification retenue est assez subtile, mais en gros les nombres entiers sont représentés exactement (et donc les calculs sur les nombres entiers tombent justes...)
Pour les nombres fractionnaires, on utilise toujours la même codification binaires, mais avec des puissances négatives de 2 (0,5, 0,25, 0,125, 0,0625,...)
Inutile de dire qu'un nombre décimal tombe rarement exactement sur une telle somme, et donc il y a une approximation, y compris dans les calculs intermédiaires. C'est ce qui explique les résultats genre 3,999999999999998 au lieu de 4.0000000000000000

Pour que ce soit plus joli, le résultat est en général affiché avec une ou deux décimales de moins et bien sur arrondi à la valeur la plus proche, de sorte que même si le calcul est légèrement inexact, le résultat à l'écran reste "rond" dans la plupart des cas.
 

Pedro51

Member
Bon, j'ai épuisé le 50/50 et le vote du public. je vais donc prendre l'appel a un ami.

J'ai cherché toute la journée et pas moyen de trouver mieux. C'est pas mon truc en fait.

symbol hundreds =b11
symbol tens =b12
symbol units =b17
symbol tenthousands =b42
symbol thousands =b43

w19=11930 'max 12000 soit 120A
w22=4927 'max 5040 soit 50,4V


watts:

bintoascii w19,tenthousands,thousands,hundreds,tens,units

b50=units-48*w22+5000/10000
b51=tens-48*w22+500/1000
w26=hundreds-48*w22+50/100
w27=thousands-48*w22+5/10
w23=tenthousands-48*w22
w23=w27+w26+b50+b51+w23

sertxd (#w23," reel = 5877,911 ")

pause 30000
goto watts
Si vous trouvez une meilleure façon de calculer, je pète les plombs.
 

BESQUEUT

Senior Member
Si vous trouvez une meilleure façon de calculer, je pète les plombs.
Meilleure, je ne sais pas... Différente en tout cas !

C'est censé donner le dixième de watt, mais on peut arrondir bien sur.
Code:
symbol hundreds =b11
symbol tens =b12
symbol units =b17
symbol tenthousands =b42
symbol thousands =b43



watts:

	w19=11998
	w22=5040
	gosub Calcul	' 6046,992 W

	w19=11999
	w22=5040
	gosub Calcul	' 6047,496 W	

	w19=12000
	w22=5040
	gosub Calcul	' 6048,000 W

	w19=11930 'max 12000 soit 120A
	w22=4927 'max 5040 soit 50,4V
	gosub Calcul	' 5877,911 W   

	pause 30000 
goto watts	


Calcul:
	bintoascii w19,tenthousands,thousands,hundreds,tens,units

	b50=units-48*w22+5000/10000
	b51=tens-48*w22+500/1000
	w26=hundreds-48*w22+50/100
	w27=thousands-48*w22+5/10
	w23=tenthousands-48*w22
	w23=w27+w26+b50+b51+w23

	w1=w19*4
	w2=w22*8**w1	' il faut encore multiplier par 2048

	w1=w2+25/50*48/20
	w2=w2*2+w1


sertxd (#w19," cA ",#w23," W  JYB: ",#w2,13)

return
Pour mémoire : à la longue, un disjoncteur coûte moins cher que les plombs... :p
 
Last edited:

Pedro51

Member
Bonjour, Alors là je suis sur le cul!

Alors pour la première partie, c'est a dire:
w1=w19*4
w2=w22*8**w1
J'avais trouvé tout seul mais pour le reste, pas moyen d'obtenir une solution.

Cela dit, j'ai pas tout compris a votre démarche et une petite explication serait la bienvenu.

En tout cas merci encore car non seulement, j'ai une solution a mon problème, et en plus je gagne en précision.
 

BESQUEUT

Senior Member
Cela dit, j'ai pas tout compris a votre démarche et une petite explication serait la bienvenue.
Pour la multiplication 64 bits, il est important que les facteurs soient les plus grands possibles de façon à obtenir la meilleure précision possible sur le résultat.
On peut essayer les puissances successives de 2 tant que la valeur maximale ne dépasse pas 32768.
Si on re-multiplie par 2, on risque de dépasser 65536...
En l&#8217;occurrence, on a choisi les facteurs 4 et 8, ce qui fait 32.
Il reste donc à multiplier par 2048 pour faire 65536, tout en divisant par 1000.
La technique est la même que celle que vous utilisez avec bin2ascii : unités, dizaines, etc...
Sauf que dans le cas de 1024 ou 2048, on peut se contenter des milliers et des unités :
Donc multiplication par 2 pour le facteur 2000/1000. (ce qui entraîne une perte de précision de 1 bit : il faut faire des choix !)
Puis pour les unités, multiplication par 48 et division par 1000.
Mais, si on fait dans cet ordre, on dépasse 65536...
Si on fait d'abord la division, on perd énormément en précision...
Donc on fait un peu des deux :
- d'abord division par 50 pour mettre à l'échelle (avec un +25 pour faire l'arrondi au mieux),
- puis multiplication par 48,
- puis division par 20 ( ce qui termine la division par 1000 : 50*20=1000)

Ne reste qu'à additionner les milliers et les unités, et voilà...
 
Last edited:

BESQUEUT

Senior Member
Encore mieux...

En poussant un peu plus l'optimisation, on gagne un ou 2 bits de précision, ce qui permet de calculer le dixième de Watt de façon presque certaine :
Code:
	A_=12000
	V=49998
	E1=59997
	E2=6
	gosub Calcul
	
	A_=12000
	V=49999
	E1=59998
	E2=8
	gosub Calcul
	
	
	A_=12000
	V=54612
	E1=65534
	E2=4
	gosub Calcul
	
	pause 10000
	goto Boucle
	

Calcul:

	P32=A_**V*6
	watt=P32**60468+5/10
	watt=A_*V+5000/10000+P32+watt

	
	sertxd (#A_,"A x ",#V,"V=",#watt,"(",#E1," ",#E2,")",13)
	return
65536=60000+5536
Pour la deuxième multiplication 32 bits, on doit multiplier le résultat précédent par 65536 et par 5536 puis diviser par 6 (puisque P32 est déjà multiplié par 6)
65536*5536/6=60467882,67
La dernière ligne ajoute les quelques unités issues de la multiplication 16bits qui influent sur le dernier chiffre de la multiplication 32 bits.
 
Last edited:

Pedro51

Member
Bonjours, J'ai compris le principe, mais pas sûr que j'applique parfaitement dans mes prochains montages. En tout cas encore merci pour tous BESQUEUT.

J’espère que çà pourra aider également d'autres membres.
 
Top