IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

Cryptomonnaies : le jeton IRON Titanium (TITAN) est passé de plus de 60 $ à pratiquement 0 $ en quelques heures
Un développeur accuse un bogue de programmation embarrassant

Le , par Stéphane le calme

750PARTAGES

13  0 
IRON Titanium Token (TITAN) a subi une perte de près de 100 % en une seule journée, passant de son record historique de 64,19 USD le 16 juin à presque 0 USD le 17 juin. « Presque » signifie que le prix a atteint 0,000000049491 USD.


Sur Twitter, Iron Finance a déclaré : « Chère communauté, veuillez retirer des liquidités de tous les pools. Nous partagerons un post-mortem dès que nous aurons une meilleure compréhension de ce bank run. La garantie USDC est disponible pour le rachat comme d’habitude ».


Le « bank run », ou panique bancaire, est un phénomène dans lequel un grand nombre de clients d’une banque craignent qu’elle ne devienne insolvable et en retirent leurs dépôts le plus vite possible. Dans la cryptosphère, on l’appelle communément un « rug pull » (expression qui renvoie à l’idée de retirer de manière brusque le tapis/support sur lequel repose une personne, par exemple. Appliquée dans le contexte de DeFi, elle renvoie au retrait subit d’un pool de liquidité).

Certains utilisateurs n’ont pas manqué de faire entendre leur déception comme Josh Cryp qui a déclaré : « Mes frais de scolarité ont disparu !!! J’avais 3 000 $ là-bas et il me reste 0,50 $. Que me reste-t-il à retirer ??!!! Ce n’est pas juste ! Celui qui a causé ça devrait être puni... Que vais-je faire maintenant ? »


Ou encore cet autre qui a noté des limites dans le logiciel : « Vous n’avez pas fixé de limite de retrait, c’est ce qui l’a fait baisser, le prix de Titan est directement proportionnel à la quantité d’Iron miné ou à la demande d’Iron. Tandis que les gens commençaient à vendre Titan, les réserves d’IRON ont commencé à augmenter et le prix de Titan a chuté ».


Que s’est-il passé ?

Un stablecoin qu’est-ce que c’est ?

Un stablecoin est un actif numérique qui réplique la valeur faciale d’une monnaie fiduciaire, souvent le dollar, comme le leader Tether (USDT) ou encore le DAI de MakerDAO. Point commun entre tous ces actifs : ils ont été créés pour protéger leurs porteurs des fluctuations spéculatives.

Les stablecoins ont été imaginés comme un outil pour se prémunir contre la forte volatilité du marché des cryptomonnaies. Après une hausse impressionnante de l’ensemble des valeurs en 2017 suivie d’une chute brutale en 2018, certains investisseurs ont en effet éprouvé le besoin d’intégrer à leur portefeuille des cryptomonnaies plus stables dans une logique d’hedging (couverture du risque). Par ailleurs, les stablecoins pourraient également être un levier contribuant à l’adoption des applications décentralisées (Dapps) s’appuyant sur la technologie blockchain.

Le cas du stablecoin IRON

TITAN appartient à Iron Finance, un projet qui a commencé à faire le lien avec la chaîne de Polygon le 18 mai dans le but de tirer parti de l’efficacité de Polygon et de ses faibles frais de transaction.

Le projet tentait de démarrer un stablecoin partiellement garanti connu sous le nom de IRON. Le stablecoin, à son tour, se compose du stablecoin de Circle et Coinbase, USDC, ainsi que TITAN, et était arrimé à 1 $. Les Stablecoins sont des cryptomonnaies dont la valeur est attachée à des actifs financiers tels que des matières premières ou des devises émises par le gouvernement dans le but de les maintenir stables.

Dans le cas d’IRON, qui reçoit sa garantie de TITAN, les utilisateurs peuvent miner de nouveaux jetons stables via un mécanisme sur le réseau d’Iron Finance en verrouillant 25 % en TITAN et 75 % en USDC.

En raison du fonctionnement de la «*tokenomics*» de ce projet DeFi particulier, lorsque de nouveaux jetons stables IRON sont minés, la demande de TITAN augmente, faisant grimper son prix. À l’inverse, lorsque le cours du TITAN chute fortement, comme ce fut le cas mercredi, l’arrimage devient instable.

« Le prix de TITAN est passé à 65 $, puis est revenu à 60 $. Cela a poussé les baleines [grands investisseurs] à commencer à vendre », a déclaré Fred Schebesta, fondateur de Finder.com.au et investisseur d’Iron Finance. « Cela a ensuite conduit à un grand désarrimage de [IRON] ».

Lorsque les gros investisseurs ont commencé à se décharger de leurs jetons TITAN, ils ont inondé le marché de jetons excédentaires, provoquant une panique bancaire.

Tout cela suggère que les stablecoins algorithmiques, qui visent à stabiliser le prix en adaptant automatiquement l’offre à la demande, comportent leurs propres risques.

La déclaration d’Iron Finance

Iron Finance a déclaré à propos de la situation :

« Nous n’avons jamais pensé que cela arriverait, mais c’est ce qui s’est passé. Nous venons de vivre la première panique bancaire crypto à grande échelle au monde.

« Vers 10 h UTC le 16 juin-2021, nous avons remarqué que certaines baleines ont commencé à retirer des liquidités de IRON/USDC, puis ont vendu TITAN à IRON puis IRON à USDC directement aux pools de liquidités au lieu de racheter IRON, ce qui a entraîné une baisse du prix du IRON. TITAN est passé de 65 $ à 30 $ en 2 heures, qui a ensuite récupéré en 1 heure à 52 $ et IRON a complètement récupéré son ancrage (peg).

« Le protocole et le code fonctionnaient comme d’habitude, et pendant que nous surveillions l’activité de la blockchain, nous pensions que c’était juste une autre correction avant la récupération. En fait, IRON a déjà été hors ancrage au moins une douzaine de fois dans toute son histoire, tandis que nos jetons d’actions (STEEL et TITAN) ont crashé beaucoup plus fort au cours des semaines précédentes. Les choses ne semblaient pas seulement éprouvées au combat, elles l’étaient. Les utilisateurs sont restés calmes et ont fait confiance au code, nous aussi.

« Tout en travaillant sur le code fork de FRAX, nous avons étudié de près tous les projets qui ont fork FRAX et ne peuvent pas conserver leur ancrage à une date ultérieure. Pour cela, nous avons déjà mis en place de nombreuses améliorations comme notre mécanisme de doubles ratios de garanties, qui s’est déjà avéré efficace pour éviter les problèmes de out-peg qui se sont produits plusieurs fois dans des situations réelles auparavant.

« Plus tard, vers 15 heures UTC, quelques gros détenteurs ont recommencé à vendre. Cette fois, après qu’ils aient commencé, de nombreux utilisateurs ont paniqué et ont commencé à racheter IRON et à vendre leur TITAN. En raison du fonctionnement de l’oracle TWAP (Time-weighted average price, une base pour les stratégies de trading) de 10 minutes, le prix au comptant du TITAN baisse encore plus par rapport au prix de rachat du TWAP. Cela a provoqué une boucle de rétroaction négative, car plus de TITAN ont été créés (à la suite de rachats de IRON) et le prix a continué à baisser. Une définition classique d’un événement irrationnel et paniqué également connu sous le nom de bank run. Au moment d’écrire ces lignes, l’offre TITAN est de 27*805 milliards.

« À certains moments, le prix du TITAN est devenu si bas, proche de 0 en fait, ce qui a amené le contrat de rachat à annuler les transactions de rachat. Nous avons déjà mis en file d’attente le correctif pour cela, afin que les gens puissent à nouveau échanger à 17h UTC.

« Ce que nous venons de vivre est la pire chose qui puisse arriver au protocole, une banque historique gérée dans l’espace cryptographique high-tech moderne. N’oubliez pas qu’Iron.finance est un stablecoin partiellement garanti, qui est similaire à la banque de réserve fractionnaire du monde moderne. Lorsque les gens paniquent et courent vers la banque pour retirer leur argent dans un court laps de temps, la banque peut s’effondrer et s’effondrera ».

Un bogue de programmation embarrassant

La situation aurait pu n’être qu’une simple fluctuation du marché et une opportunité d’arbitrage pour l’ensemble de cryptographie, sans l’effet de la variation drastique des prix sur le contrat intelligent d’IRON, le code exécuté sur la BinanceSmartChain qui régit les transactions.

En termes simples, le contrat intelligent a échoué alors que le prix approchait de zéro.

« Puisque le prix du TITAN est tombé à 0, le contrat ne permet pas de rachats », a expliqué Iron Finance, la firme à l’origine du stablecoin partiel IRON, dans un communiqué mercredi. « Nous devrons attendre 12 heures pour que le délai soit écoulé avant que les rachats par l’USDC ne soient à nouveau possibles ».

Dans un billet publié jeudi sur Medium, une personne non identifiée a affirmé que la raison en était que le code de contrat intelligent IRON pour racheter (l’échanger contre une autre devise) le stablecoin pas si stable contient une erreur de limite :

Code JavaScript : Sélectionner tout
require(_share_price > 0, “Invalid share price”);

Voici le code qu’il a analysé :

Code JavaScript : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
// SPDX-License-Identifier: MIT 
  
pragma solidity 0.8.4; 
  
import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; 
import "@openzeppelin/contracts/access/Ownable.sol"; 
import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; 
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; 
  
import "./interfaces/IShare.sol"; 
import "./interfaces/IDollar.sol"; 
import "./interfaces/ITreasury.sol"; 
import "./interfaces/IOracle.sol"; 
import "./interfaces/IPool.sol"; 
  
contract Pool is Ownable, ReentrancyGuard, Initializable, IPool { 
    using SafeERC20 for ERC20; 
  
    /* ========== ADDRESSES ================ */ 
    address public oracle; 
    address public collateral; 
    address public dollar; 
    address public treasury; 
    address public share; 
  
    /* ========== STATE VARIABLES ========== */ 
  
    mapping(address => uint256) public redeem_share_balances; 
    mapping(address => uint256) public redeem_collateral_balances; 
  
    uint256 public override unclaimed_pool_collateral; 
    uint256 public unclaimed_pool_share; 
  
    mapping(address => uint256) public last_redeemed; 
  
    // Constants for various precisions 
    uint256 private constant PRICE_PRECISION = 1e6; 
    uint256 private constant COLLATERAL_RATIO_PRECISION = 1e6; 
    uint256 private constant COLLATERAL_RATIO_MAX = 1e6; 
  
    // Number of decimals needed to get to 18 
    uint256 private missing_decimals; 
  
    // Number of blocks to wait before being able to collectRedemption() 
    uint256 public redemption_delay = 1; 
  
    // AccessControl state variables 
    bool public mint_paused = false; 
    bool public redeem_paused = false; 
  
    /* ========== MODIFIERS ========== */ 
  
    modifier onlyTreasury() { 
        require(msg.sender == treasury, "!treasury"); 
        _; 
    } 
  
    /* ========== CONSTRUCTOR ========== */ 
  
    function initialize( 
        address _dollar, 
        address _share, 
        address _collateral, 
        address _treasury 
    ) external initializer onlyOwner { 
        dollar = _dollar; 
        share = _share; 
        collateral = _collateral; 
        treasury = _treasury; 
        missing_decimals = 18 - ERC20(_collateral).decimals(); 
    } 
  
    /* ========== VIEWS ========== */ 
  
    function info() 
        external 
        view 
        returns ( 
            uint256, 
            uint256, 
            uint256, 
            bool, 
            bool 
        ) 
    { 
        return ( 
            unclaimed_pool_collateral, // unclaimed amount of COLLATERAL 
            unclaimed_pool_share, // unclaimed amount of SHARE 
            getCollateralPrice(), // collateral price 
            mint_paused, 
            redeem_paused 
        ); 
    } 
  
    function collateralReserve() public view returns (address) { 
        return ITreasury(treasury).collateralReserve(); 
    } 
  
    function getCollateralPrice() public view override returns (uint256) { 
        return IOracle(oracle).consult(); 
    } 
  
    /* ========== PUBLIC FUNCTIONS ========== */ 
  
    function mint( 
        uint256 _collateral_amount, 
        uint256 _share_amount, 
        uint256 _dollar_out_min 
    ) external { 
        require(mint_paused == false, "Minting is paused"); 
        (, uint256 _share_price, , uint256 _tcr, , , uint256 _minting_fee, ) = ITreasury(treasury).info(); 
        require(_share_price > 0, "Invalid share price"); 
        uint256 _price_collateral = getCollateralPrice(); 
        uint256 _total_dollar_value = 0; 
        uint256 _required_share_amount = 0; 
        if (_tcr > 0) { 
            uint256 _collateral_value = ((_collateral_amount * (10**missing_decimals)) * _price_collateral) / PRICE_PRECISION; 
            _total_dollar_value = (_collateral_value * COLLATERAL_RATIO_PRECISION) / _tcr; 
            if (_tcr < COLLATERAL_RATIO_MAX) { 
                _required_share_amount = ((_total_dollar_value - _collateral_value) * PRICE_PRECISION) / _share_price; 
            } 
        } else { 
            _total_dollar_value = (_share_amount * _share_price) / PRICE_PRECISION; 
            _required_share_amount = _share_amount; 
        } 
        uint256 _actual_dollar_amount = _total_dollar_value - ((_total_dollar_value * _minting_fee) / PRICE_PRECISION); 
        require(_dollar_out_min <= _actual_dollar_amount, "slippage"); 
  
        if (_required_share_amount > 0) { 
            require(_required_share_amount <= _share_amount, "Not enough SHARE input"); 
            IShare(share).poolBurnFrom(msg.sender, _required_share_amount); 
        } 
        if (_collateral_amount > 0) { 
            _transferCollateralToReserve(msg.sender, _collateral_amount); 
        } 
        IDollar(dollar).poolMint(msg.sender, _actual_dollar_amount); 
    } 
  
    function redeem( 
        uint256 _dollar_amount, 
        uint256 _share_out_min, 
        uint256 _collateral_out_min 
    ) external { 
        require(redeem_paused == false, "Redeeming is paused"); 
        (, uint256 _share_price, , , uint256 _ecr, , , uint256 _redemption_fee) = ITreasury(treasury).info(); 
        uint256 _collateral_price = getCollateralPrice(); 
        require(_collateral_price > 0, "Invalid collateral price"); 
        require(_share_price > 0, "Invalid share price"); 
        uint256 _dollar_amount_post_fee = _dollar_amount - ((_dollar_amount * _redemption_fee) / PRICE_PRECISION); 
        uint256 _collateral_output_amount = 0; 
        uint256 _share_output_amount = 0; 
  
        if (_ecr < COLLATERAL_RATIO_MAX) { 
            uint256 _share_output_value = _dollar_amount_post_fee - ((_dollar_amount_post_fee * _ecr) / PRICE_PRECISION); 
            _share_output_amount = (_share_output_value * PRICE_PRECISION) / _share_price; 
        } 
  
        if (_ecr > 0) { 
            uint256 _collateral_output_value = ((_dollar_amount_post_fee * _ecr) / PRICE_PRECISION) / (10**missing_decimals); 
            _collateral_output_amount = (_collateral_output_value * PRICE_PRECISION) / _collateral_price; 
        } 
  
        // Check if collateral balance meets and meet output expectation 
        uint256 _totalCollateralBalance = ITreasury(treasury).globalCollateralBalance(); 
        require(_collateral_output_amount <= _totalCollateralBalance, "<collateralBalance"); 
        require(_collateral_out_min <= _collateral_output_amount && _share_out_min <= _share_output_amount, ">slippage"); 
  
        if (_collateral_output_amount > 0) { 
            redeem_collateral_balances[msg.sender] = redeem_collateral_balances[msg.sender] + _collateral_output_amount; 
            unclaimed_pool_collateral = unclaimed_pool_collateral + _collateral_output_amount; 
        } 
  
        if (_share_output_amount > 0) { 
            redeem_share_balances[msg.sender] = redeem_share_balances[msg.sender] + _share_output_amount; 
            unclaimed_pool_share = unclaimed_pool_share + _share_output_amount; 
        } 
  
        last_redeemed[msg.sender] = block.number; 
  
        // Move all external functions to the end 
        IDollar(dollar).poolBurnFrom(msg.sender, _dollar_amount); 
        if (_share_output_amount > 0) { 
            _mintShareToCollateralReserve(_share_output_amount); 
        } 
    } 
  
    function collectRedemption() external { 
        require((last_redeemed[msg.sender] + redemption_delay) <= block.number, "<redemption_delay"); 
  
        bool _send_share = false; 
        bool _send_collateral = false; 
        uint256 _share_amount; 
        uint256 _collateral_amount; 
  
        // Use Checks-Effects-Interactions pattern 
        if (redeem_share_balances[msg.sender] > 0) { 
            _share_amount = redeem_share_balances[msg.sender]; 
            redeem_share_balances[msg.sender] = 0; 
            unclaimed_pool_share = unclaimed_pool_share - _share_amount; 
            _send_share = true; 
        } 
  
        if (redeem_collateral_balances[msg.sender] > 0) { 
            _collateral_amount = redeem_collateral_balances[msg.sender]; 
            redeem_collateral_balances[msg.sender] = 0; 
            unclaimed_pool_collateral = unclaimed_pool_collateral - _collateral_amount; 
            _send_collateral = true; 
        } 
  
        if (_send_share) { 
            _requestTransferShare(msg.sender, _share_amount); 
        } 
  
        if (_send_collateral) { 
            _requestTransferCollateral(msg.sender, _collateral_amount); 
        } 
    } 
  
    /* ========== INTERNAL FUNCTIONS ========== */ 
  
    function _transferCollateralToReserve(address _sender, uint256 _amount) internal { 
        address _reserve = collateralReserve(); 
        require(_reserve != address(0), "Invalid reserve address"); 
        ERC20(collateral).safeTransferFrom(_sender, _reserve, _amount); 
    } 
  
    function _mintShareToCollateralReserve(uint256 _amount) internal { 
        address _reserve = collateralReserve(); 
        require(_reserve != address(0), "Invalid reserve address"); 
        IShare(share).poolMint(_reserve, _amount); 
    } 
  
    function _requestTransferCollateral(address _receiver, uint256 _amount) internal { 
        ITreasury(treasury).requestTransfer(collateral, _receiver, _amount); 
    } 
  
    function _requestTransferShare(address _receiver, uint256 _amount) internal { 
        ITreasury(treasury).requestTransfer(share, _receiver, _amount); 
    } 
  
    /* ========== RESTRICTED FUNCTIONS ========== */ 
  
    function toggleMinting() external onlyOwner { 
        mint_paused = !mint_paused; 
    } 
  
    function toggleRedeeming() external onlyOwner { 
        redeem_paused = !redeem_paused; 
    } 
  
    function setOracle(address _oracle) external onlyOwner { 
        require(_oracle != address(0), "Invalid address"); 
        oracle = _oracle; 
    } 
  
    function setRedemptionDelay(uint256 _redemption_delay) external onlyOwner { 
        redemption_delay = _redemption_delay; 
    } 
  
    function setTreasury(address _treasury) external onlyOwner { 
        require(_treasury != address(0), "Invalid address"); 
        treasury = _treasury; 
        emit TreasuryChanged(_treasury); 
    } 
  
    // EVENTS 
    event TreasuryChanged(address indexed newTreasury); 
}

Si c’est correct, l’utilisation de l’opérateur ">" (supérieur à) plutôt que ">=" (supérieur ou égal à) signifierait qu’une valeur TITAN évaluée comme zéro (qui dépend de la précision numérique du calcul) serait être considéré comme invalide et serait refusé pour le rachat.

Quoi qu’il en soit, cette affirmation n’a pas été confirmée par Iron Finance, et ce dernier s’est refusé à tout commentaire concernant cette éventualité. Cependant, la propre description de l’incident par Iron Finance décrit un scénario cohérent avec ce qui a été proposé par l’auteur non identifié de Medium :

« À certains moments, le prix du TITAN est devenu si bas, proche de 0 en fait, ce qui a amené le contrat de rachat à annuler les transactions de rachat », a déclaré Iron Finance dans son rapport d’incident jeudi (vers 16 heures UTC). « Nous avons déjà mis en file d’attente le correctif pour cela, afin que les gens puissent à nouveau échanger à 17h UTC ».

Sources : communiqué Iron Finance, tweets Iron Finance (1, 2), en savoir plus sur IRON, GitHub (code contrats), individu non identifié

Une erreur dans cette actualité ? Signalez-le nous !

Avatar de Fagus
Membre éclairé https://www.developpez.com
Le 21/06/2021 à 13:17
Code : Sélectionner tout
print(.1+.1+.1-.3)
Code : Sélectionner tout
1
2
5.551115123125783e-17
** Process exited - Return Code: 0 **
C'est pas une bonne pratique universelle en finance d'utiliser un langage ou une lib de calcul flottant à haute précision et de tester les problèmes d'arrondi ?
1  0 
Avatar de electroremy
Membre éclairé https://www.developpez.com
Le 24/06/2021 à 9:52
C'est bizarre... l'usage de nombre entiers (avec une unité valant une fraction de centimes) ne suffit-elle pas à éviter ce genre de problèmes d'instabilité numérique ?

Les flotants c'est pratique mais vicieux...

Par exemple dans mes applications type CAO, toutes mes coordonnées (X, Y, et Z pour la 3D) sont des nombres entiers.

une unité équivaut à un micron ce qui est suffisant étant donné la précision des machines pilotées (bien sûr, on peut aller plus bas)

En effet, avec des nombres à virgule flottante, la précision absolue dépend de la valeur de la coordonnées (meilleure quand la coordonnée a une valeur faible) et du coup à chaque translation, la valeur des coordonnées change, donc à chaque translation on déforme un peu ses pièces
De même, des formes identiques mais à des coordonnées différentes ne sont pas identiques.
Avec certains algorithmes sensibles (collision, fusion de polygones) cela engendre une pagaille monstrueuse

Je trouve que c'est un point qui n'est pas suffisamment enseigné en cours de programmation, et il est à l'origine de bugs très difficiles à résoudre.
1  0 
Avatar de Aiigl59
Membre habitué https://www.developpez.com
Le 24/06/2021 à 12:21
Il est évident que ce qui ne vaut rien au départ ne vaudra toujours rien à l'arrivée, quelque soient les spéculations appliquées dessus...
Il n'est pas donné aux hommes ni à ses machines de créer "ex-nihilo", et cela se vérifiera toujours...
Les perdants dans l'histoire seront ceux qui sont attiré par ces "miroirs aux alouettes", l'histoire se répète, rien de nouveau sous le soleil...
Salutations à toutes et à tous !
1  0 
Avatar de pvincent
Membre confirmé https://www.developpez.com
Le 25/06/2021 à 17:55
Citation Envoyé par pmithrandir Voir le message
C'est effectivement une astuce largement sous étudiée.
Privilégier les entier a la place des doubles reste une manière d'optimiser son code rapidement, et de le simplifier aussi souvent
Le langage Forth (https://fr.wikipedia.org/wiki/Forth_(langage)), conçu jadis pour faire des calculs astronomique de haute précision ne manipulait au départ que des entiers.
1  0 
Avatar de mith06
Membre éclairé https://www.developpez.com
Le 21/06/2021 à 14:04
dans le même genre
Code : Sélectionner tout
1
2
3
4
5
#include <stdio.h>
int main(){
    printf("%d",(1LL<<53)+1.0 == (1LL<<53));
    return 0;
}
Code : Sélectionner tout
1
2
3
1

...Program finished with exit code 0
0  0 
Avatar de pmithrandir
Expert éminent https://www.developpez.com
Le 24/06/2021 à 15:43
Citation Envoyé par electroremy Voir le message
C'est bizarre... l'usage de nombre entiers (avec une unité valant une fraction de centimes) ne suffit-elle pas à éviter ce genre de problèmes d'instabilité numérique ?

Les flotants c'est pratique mais vicieux...

Par exemple dans mes applications type CAO, toutes mes coordonnées (X, Y, et Z pour la 3D) sont des nombres entiers.

une unité équivaut à un micron ce qui est suffisant étant donné la précision des machines pilotées (bien sûr, on peut aller plus bas)

En effet, avec des nombres à virgule flottante, la précision absolue dépend de la valeur de la coordonnées (meilleure quand la coordonnée a une valeur faible) et du coup à chaque translation, la valeur des coordonnées change, donc à chaque translation on déforme un peu ses pièces
De même, des formes identiques mais à des coordonnées différentes ne sont pas identiques.
Avec certains algorithmes sensibles (collision, fusion de polygones) cela engendre une pagaille monstrueuse

Je trouve que c'est un point qui n'est pas suffisamment enseigné en cours de programmation, et il est à l'origine de bugs très difficiles à résoudre.
C'est effectivement une astuce largement sous étudiée.
Privilégier les entier a la place des doubles reste une manière d'optimiser son code rapidement, et de le simplifier aussi souvent
0  0