Considérons les quatre pourcentages ci-dessous, représentés par des nombres float
:
13.626332%
47.989636%
9.596008%
28.788024%
-----------
100.000000%
Je dois représenter ces pourcentages sous forme de nombres entiers. Si j’utilise simplement Math.round()
, j’ai un total de 101%.
14 + 48 + 10 + 29 = 101
Si j'utilise parseInt()
, je termine avec un total de 97%.
13 + 47 + 9 + 28 = 97
Qu'est-ce qu'un bon algorithme pour représenter un nombre quelconque de pourcentages tout en maintenant un total de 100%?
Edit : Après avoir lu certains commentaires et réponses, il existe clairement de nombreux moyens de résoudre ce problème.
Dans mon esprit, pour rester fidèle aux chiffres, le résultat "correct" est celui qui minimise l'erreur globale, défini par le degré d'erreur que l'arrondi introduirait par rapport à la valeur réelle:
value rounded error decision
----------------------------------------------------
13.626332 14 2.7% round up (14)
47.989636 48 0.0% round up (48)
9.596008 10 4.0% don't round up (9)
28.788024 29 2.7% round up (29)
En cas d’égalité (3,33, 3,33, 3,33), une décision arbitraire peut être prise (par exemple 3, 4, 3).
Comme aucune des réponses ici ne semble résoudre le problème correctement, voici ma version semi-obscurcie utilisant underscorejs :
function foo(l, target) {
var off = target - _.reduce(l, function(acc, x) { return acc + Math.round(x) }, 0);
return _.chain(l).
sortBy(function(x) { return Math.round(x) - x }).
map(function(x, i) { return Math.round(x) + (off > i) - (i >= (l.length + off)) }).
value();
}
foo([13.626332, 47.989636, 9.596008, 28.788024], 100) // => [48, 29, 14, 9]
foo([16.666, 16.666, 16.666, 16.666, 16.666, 16.666], 100) // => [17, 17, 17, 17, 16, 16]
foo([33.333, 33.333, 33.333], 100) // => [34, 33, 33]
foo([33.3, 33.3, 33.3, 0.1], 100) // => [34, 33, 33, 0]
Il existe de nombreuses façons de le faire, à condition que vous ne craigniez pas de vous fier aux données décimales d'origine.
La première méthode, et peut-être la plus populaire, serait la Méthode du plus grand reste
Ce qui est fondamentalement:
Dans votre cas, cela ressemblerait à ceci:
13.626332%
47.989636%
9.596008%
28.788024%
Si vous prenez les parties entières, vous obtenez
13
47
9
28
ce qui donne 97, et vous voulez en ajouter trois autres. Maintenant, vous regardez les parties décimales, qui sont
.626332%
.989636%
.596008%
.788024%
et prenez les plus gros jusqu'à ce que le total atteigne 100. Vous obtiendriez donc:
14
48
9
29
Sinon, vous pouvez simplement choisir d'afficher une décimale au lieu des valeurs entières. Ainsi, les nombres seraient 48,3 et 23,9, etc. Cela réduirait considérablement la variance de 100.
La meilleure façon de le faire est probablement de garder un compte courant (non intégral) de votre position et de arrondir la valeur , puis de l'utiliser avec l'historique pour déterminer quelle valeur doit être utilisée. Par exemple, en utilisant les valeurs que vous avez données:
Value CumulValue CumulRounded PrevBaseline Need
--------- ---------- ------------ ------------ ----
0
13.626332 13.626332 14 0 14 ( 14 - 0)
47.989636 61.615968 62 14 48 ( 62 - 14)
9.596008 71.211976 71 62 9 ( 71 - 62)
28.788024 100.000000 100 71 29 (100 - 71)
---
100
A chaque étape, vous n’arrondez pas le nombre lui-même. Au lieu de cela, arrondissez la valeur accumulated et calculez le meilleur nombre entier qui atteint cette valeur depuis la référence précédente - cette référence est la valeur cumulative (arrondie) de la ligne précédente.
Cela fonctionne parce que vous ne perdez pas d'informations à chaque étape, mais que vous les utilisez de manière plus intelligente. Les valeurs arrondies "correctes" sont dans la dernière colonne et vous pouvez voir qu'elles totalisent 100.
Le but de l'arrondi est de générer le moins d'erreur possible. Lorsque vous arrondissez une valeur unique, ce processus est simple et direct et la plupart des gens le comprennent facilement. Lorsque vous arrondissez plusieurs nombres en même temps, le processus devient plus compliqué - vous devez définir comment les erreurs vont se combiner, c’est-à-dire ce qui doit être minimisé.
Le réponse bien votée de Varun Vohra minimise la somme des erreurs absolues et est très simple à mettre en œuvre. Toutefois, il n’ya pas de cas Edge qu’il ne gère pas - quel devrait être le résultat de l’arrondi de 24.25, 23.25, 27.25, 25.25
? Un de ceux-ci doit être arrondi au lieu de bas. Vous choisiriez probablement de manière arbitraire le premier ou le dernier de la liste.
Il est peut-être préférable d’utiliser l’erreur relative plutôt que l’erreur absolute. Arrondir 23,25 jusqu'à 24 le change de 3,2%, tandis que arrondir 27,25 à 28 le change seulement de 2,8%. Maintenant, il y a un gagnant clair.
Il est possible de modifier cela encore plus. Une technique courante consiste à square chaque erreur, de sorte que les grandes erreurs comptent de manière disproportionnée plus que les petites. Je voudrais également utiliser un diviseur non linéaire pour obtenir l'erreur relative - il ne semble pas exact qu'une erreur à 1% soit 99 fois plus importante qu'une erreur à 99%. Dans le code ci-dessous, j'ai utilisé la racine carrée.
L'algorithme complet est le suivant:
Vous pouvez toujours avoir plus d'une combinaison avec la même somme d'erreur, par exemple 33.3333333, 33.3333333, 33.3333333
. Ceci est inévitable et le résultat sera complètement arbitraire. Le code que je donne ci-dessous préfère arrondir les valeurs à gauche.
Tout mettre en place en Python ressemble à ceci.
def error_gen(actual, rounded):
divisor = sqrt(1.0 if actual < 1.0 else actual)
return abs(rounded - actual) ** 2 / divisor
def round_to_100(percents):
if not isclose(sum(percents), 100):
raise ValueError
n = len(percents)
rounded = [int(x) for x in percents]
up_count = 100 - sum(rounded)
errors = [(error_gen(percents[i], rounded[i] + 1) - error_gen(percents[i], rounded[i]), i) for i in range(n)]
rank = sorted(errors)
for i in range(up_count):
rounded[rank[i][1]] += 1
return rounded
>>> round_to_100([13.626332, 47.989636, 9.596008, 28.788024])
[14, 48, 9, 29]
>>> round_to_100([33.3333333, 33.3333333, 33.3333333])
[34, 33, 33]
>>> round_to_100([24.25, 23.25, 27.25, 25.25])
[24, 23, 28, 25]
>>> round_to_100([1.25, 2.25, 3.25, 4.25, 89.0])
[1, 2, 3, 4, 90]
Comme vous pouvez le constater avec ce dernier exemple, cet algorithme est toujours capable de fournir des résultats non intuitifs. Bien que 89.0 ne nécessite aucun arrondi, l’une des valeurs de cette liste doit être arrondie; l'erreur relative la plus faible résulte de l'arrondissement de cette valeur élevée plutôt que des solutions beaucoup plus petites.
Cette réponse préconisait à l’origine de passer par toutes les combinaisons possibles d’arrondis/décroissants, mais comme le soulignent les commentaires, une méthode plus simple fonctionne mieux. L'algorithme et le code reflètent cette simplification.
NE PAS additionner les nombres arrondis. Vous allez avoir des résultats inexacts. Le total pourrait être considérablement réduit en fonction du nombre de termes et de la distribution des fractions.
Affiche les nombres arrondis mais somme les valeurs réelles. Selon la manière dont vous présentez les chiffres, la manière de procéder varie. De cette façon, vous obtenez
14 48 dix 29 __ 100
De toute façon, vous allez avoir des divergences. Dans votre exemple, il n’ya aucun moyen d’indiquer des nombres qui totalisent 100 sans "arrondir" une valeur dans le mauvais sens (la moindre erreur serait de changer 9,596 en 9)
MODIFIER
Vous devez choisir entre l’un des éléments suivants:
La plupart du temps, s’agissant du pourcentage n ° 3, c’est la meilleure option car elle est plus évidente lorsque le total est égal à 101% que lorsque les éléments individuels ne totalisent pas 100, et que vous conservez la précision des éléments. "Arrondir" 9.596 à 9 est inexact à mon avis.
Pour expliquer cela, j'ajoute parfois une note de bas de page expliquant que les valeurs individuelles sont arrondies et ne totalisent peut-être pas 100%. Toute personne qui comprend l'arrondi devrait être en mesure de comprendre cette explication.
J'ai écrit un assistant d'arrondi à la version C #, l'algorithme est le même que La réponse de Varun Vohra , espérons que cela aide.
public static List<decimal> GetPerfectRounding(List<decimal> original,
decimal forceSum, int decimals)
{
var rounded = original.Select(x => Math.Round(x, decimals)).ToList();
Debug.Assert(Math.Round(forceSum, decimals) == forceSum);
var delta = forceSum - rounded.Sum();
if (delta == 0) return rounded;
var deltaUnit = Convert.ToDecimal(Math.Pow(0.1, decimals)) * Math.Sign(delta);
List<int> applyDeltaSequence;
if (delta < 0)
{
applyDeltaSequence = original
.Zip(Enumerable.Range(0, int.MaxValue), (x, index) => new { x, index })
.OrderBy(a => original[a.index] - rounded[a.index])
.ThenByDescending(a => a.index)
.Select(a => a.index).ToList();
}
else
{
applyDeltaSequence = original
.Zip(Enumerable.Range(0, int.MaxValue), (x, index) => new { x, index })
.OrderByDescending(a => original[a.index] - rounded[a.index])
.Select(a => a.index).ToList();
}
Enumerable.Repeat(applyDeltaSequence, int.MaxValue)
.SelectMany(x => x)
.Take(Convert.ToInt32(delta/deltaUnit))
.ForEach(index => rounded[index] += deltaUnit);
return rounded;
}
Il réussit le test unitaire suivant:
[TestMethod]
public void TestPerfectRounding()
{
CollectionAssert.AreEqual(Utils.GetPerfectRounding(
new List<decimal> {3.333m, 3.334m, 3.333m}, 10, 2),
new List<decimal> {3.33m, 3.34m, 3.33m});
CollectionAssert.AreEqual(Utils.GetPerfectRounding(
new List<decimal> {3.33m, 3.34m, 3.33m}, 10, 1),
new List<decimal> {3.3m, 3.4m, 3.3m});
CollectionAssert.AreEqual(Utils.GetPerfectRounding(
new List<decimal> {3.333m, 3.334m, 3.333m}, 10, 1),
new List<decimal> {3.3m, 3.4m, 3.3m});
CollectionAssert.AreEqual(Utils.GetPerfectRounding(
new List<decimal> { 13.626332m, 47.989636m, 9.596008m, 28.788024m }, 100, 0),
new List<decimal> {14, 48, 9, 29});
CollectionAssert.AreEqual(Utils.GetPerfectRounding(
new List<decimal> { 16.666m, 16.666m, 16.666m, 16.666m, 16.666m, 16.666m }, 100, 0),
new List<decimal> { 17, 17, 17, 17, 16, 16 });
CollectionAssert.AreEqual(Utils.GetPerfectRounding(
new List<decimal> { 33.333m, 33.333m, 33.333m }, 100, 0),
new List<decimal> { 34, 33, 33 });
CollectionAssert.AreEqual(Utils.GetPerfectRounding(
new List<decimal> { 33.3m, 33.3m, 33.3m, 0.1m }, 100, 0),
new List<decimal> { 34, 33, 33, 0 });
}
Vous pouvez essayer de garder une trace de votre erreur en raison de l'arrondissement, puis de l'arrondir dans le sens contraire du grain si l'erreur accumulée est supérieure à la fraction du nombre en cours.
13.62 -> 14 (+.38)
47.98 -> 48 (+.02 (+.40 total))
9.59 -> 10 (+.41 (+.81 total))
28.78 -> 28 (round down because .81 > .78)
------------
100
Je ne sais pas si cela fonctionnerait en général, mais cela semble fonctionner de manière similaire si l'ordre est inversé:
28.78 -> 29 (+.22)
9.59 -> 9 (-.37; rounded down because .59 > .22)
47.98 -> 48 (-.35)
13.62 -> 14 (+.03)
------------
100
Je suis sûr qu'il y a des cas où Edge pourrait s'effondrer, mais toute approche sera au moins quelque peu arbitraire puisque vous modifiez essentiellement vos données d'entrée.
J'ai déjà écrit un outil non arrondi pour trouver la perturbation minimale d'un ensemble de nombres correspondant à un objectif. C'était un problème différent, mais on pourrait en théorie utiliser une idée similaire ici. Dans ce cas, nous avons un ensemble de choix.
Ainsi, pour le premier élément, nous pouvons arrondir le nombre à 14 ou le réduire à 13. Le coût (au sens binaire de la programmation entière) est moins pour le arrondi que pour le arrondi, car il faut arrondir déplacez cette valeur sur une plus grande distance. De la même manière, nous pouvons arrondir chaque nombre vers le haut ou le bas, de sorte que nous devons choisir parmi 16 choix.
13.626332
47.989636
9.596008
+ 28.788024
-----------
100.000000
Normalement, je résoudrais le problème général dans MATLAB, ici en utilisant bintprog, un outil de programmation entier binaire, mais il n’ya que quelques choix à tester. Il est donc assez facile, avec de simples boucles, de tester chacune des 16 alternatives. Par exemple, supposons que nous arrondissions cet ensemble comme suit:
Original Rounded Absolute error
13.626 13 0.62633
47.99 48 0.01036
9.596 10 0.40399
+ 28.788 29 0.21198
---------------------------------------
100.000 100 1.25266
L'erreur absolue totale est 1.25266. Il peut être légèrement réduit par l’arrondi alternatif suivant:
Original Rounded Absolute error
13.626 14 0.37367
47.99 48 0.01036
9.596 9 0.59601
+ 28.788 29 0.21198
---------------------------------------
100.000 100 1.19202
En fait, ce sera la solution optimale en termes d'erreur absolue. Bien sûr, s’il y avait 20 termes, l’espace de recherche sera de taille 2 ^ 20 = 1048576. Pour 30 ou 40 termes, cet espace aura une taille importante. Dans ce cas, vous devrez utiliser un outil capable de rechercher efficacement dans l'espace, en utilisant éventuellement un schéma de branche et lié.
Je pense que ce qui suit réalisera ce que vous recherchez
function func( orig, target ) {
var i = orig.length, j = 0, total = 0, change, newVals = [], next, factor1, factor2, len = orig.length, marginOfErrors = [];
// map original values to new array
while( i-- ) {
total += newVals[i] = Math.round( orig[i] );
}
change = total < target ? 1 : -1;
while( total !== target ) {
// Iterate through values and select the one that once changed will introduce
// the least margin of error in terms of itself. e.g. Incrementing 10 by 1
// would mean an error of 10% in relation to the value itself.
for( i = 0; i < len; i++ ) {
next = i === len - 1 ? 0 : i + 1;
factor2 = errorFactor( orig[next], newVals[next] + change );
factor1 = errorFactor( orig[i], newVals[i] + change );
if( factor1 > factor2 ) {
j = next;
}
}
newVals[j] += change;
total += change;
}
for( i = 0; i < len; i++ ) { marginOfErrors[i] = newVals[i] && Math.abs( orig[i] - newVals[i] ) / orig[i]; }
// Math.round() causes some problems as it is difficult to know at the beginning
// whether numbers should have been rounded up or down to reduce total margin of error.
// This section of code increments and decrements values by 1 to find the number
// combination with least margin of error.
for( i = 0; i < len; i++ ) {
for( j = 0; j < len; j++ ) {
if( j === i ) continue;
var roundUpFactor = errorFactor( orig[i], newVals[i] + 1) + errorFactor( orig[j], newVals[j] - 1 );
var roundDownFactor = errorFactor( orig[i], newVals[i] - 1) + errorFactor( orig[j], newVals[j] + 1 );
var sumMargin = marginOfErrors[i] + marginOfErrors[j];
if( roundUpFactor < sumMargin) {
newVals[i] = newVals[i] + 1;
newVals[j] = newVals[j] - 1;
marginOfErrors[i] = newVals[i] && Math.abs( orig[i] - newVals[i] ) / orig[i];
marginOfErrors[j] = newVals[j] && Math.abs( orig[j] - newVals[j] ) / orig[j];
}
if( roundDownFactor < sumMargin ) {
newVals[i] = newVals[i] - 1;
newVals[j] = newVals[j] + 1;
marginOfErrors[i] = newVals[i] && Math.abs( orig[i] - newVals[i] ) / orig[i];
marginOfErrors[j] = newVals[j] && Math.abs( orig[j] - newVals[j] ) / orig[j];
}
}
}
function errorFactor( oldNum, newNum ) {
return Math.abs( oldNum - newNum ) / oldNum;
}
return newVals;
}
func([16.666, 16.666, 16.666, 16.666, 16.666, 16.666], 100); // => [16, 16, 17, 17, 17, 17]
func([33.333, 33.333, 33.333], 100); // => [34, 33, 33]
func([33.3, 33.3, 33.3, 0.1], 100); // => [34, 33, 33, 0]
func([13.25, 47.25, 11.25, 28.25], 100 ); // => [13, 48, 11, 28]
func( [25.5, 25.5, 25.5, 23.5], 100 ); // => [25, 25, 26, 24]
Une dernière chose, j'ai lancé la fonction en utilisant les nombres donnés à l'origine dans la question pour les comparer
func([13.626332, 47.989636, 9.596008, 28.788024], 100); // => [48, 29, 13, 10]
C'était différent de ce que la question voulait => [48, 29, 14, 9]. Je ne pouvais pas comprendre cela avant de regarder la marge d'erreur totale
-------------------------------------------------
| original | question | % diff | mine | % diff |
-------------------------------------------------
| 13.626332 | 14 | 2.74% | 13 | 4.5% |
| 47.989636 | 48 | 0.02% | 48 | 0.02% |
| 9.596008 | 9 | 6.2% | 10 | 4.2% |
| 28.788024 | 29 | 0.7% | 29 | 0.7% |
-------------------------------------------------
| Totals | 100 | 9.66% | 100 | 9.43% |
-------------------------------------------------
Essentiellement, le résultat de ma fonction introduit le moins d’erreurs possible.
Violon ici
Je ne suis pas sûr du niveau de précision dont vous avez besoin, mais ce que je ferais, c’est tout simplement d’ajouter 1 le premier nombre n
, n
étant le plafond de la somme totale des décimales. Dans ce cas, il s'agit de 3
, donc j'ajouterais 1 aux 3 premiers éléments et répartirais le reste. Bien sûr, ce n’est pas très précis. Certains chiffres peuvent être arrondis à la hausse ou à la baisse, mais cela fonctionne bien et donnera toujours un résultat de 100%.
Donc, [ 13.626332, 47.989636, 9.596008, 28.788024 ]
serait [14, 48, 10, 28]
car Math.ceil(.626332+.989636+.596008+.788024) == 3
function evenRound( arr ) {
var decimal = -~arr.map(function( a ){ return a % 1 })
.reduce(function( a,b ){ return a + b }); // Ceil of total sum of decimals
for ( var i = 0; i < decimal; ++i ) {
arr[ i ] = ++arr[ i ]; // compensate error by adding 1 the the first n items
}
return arr.map(function( a ){ return ~~a }); // floor all other numbers
}
var nums = evenRound( [ 13.626332, 47.989636, 9.596008, 28.788024 ] );
var total = nums.reduce(function( a,b ){ return a + b }); //=> 100
Vous pouvez toujours informer les utilisateurs que les chiffres sont arrondis et peuvent ne pas être super précis ...
Si vous devez vraiment les arrondir, il y a déjà de très bonnes suggestions ici (plus gros reste, moins erreur relative, etc.).
Il y a aussi déjà une bonne raison de ne pas arrondir (vous aurez au moins un chiffre qui "aura l'air mieux" mais qui est "faux"), et comment résoudre ce problème (avertissez vos lecteurs) et c'est ce que je fais.
Permettez-moi d'ajouter le "mauvais" numéro.
Supposons que vous avez trois événements/entités/... avec quelques pourcentages que vous estimez comme:
DAY 1
who | real | app
----|-------|------
A | 33.34 | 34
B | 33.33 | 33
C | 33.33 | 33
Plus tard, les valeurs changent légèrement, à
DAY 2
who | real | app
----|-------|------
A | 33.35 | 33
B | 33.36 | 34
C | 33.29 | 33
La première table a le problème déjà mentionné d'avoir un "mauvais" numéro: 33.34 est plus proche de 33 que de 34.
Mais maintenant, vous avez une plus grande erreur. En comparant les jours 2 et 1, le pourcentage réel de A a augmenté de 0,01%, mais l’approximation montre une diminution de 1%.
C'est une erreur qualitative, probablement bien pire que l'erreur quantitative initiale.
On pourrait imaginer une approximation pour l’ensemble, mais il se peut que vous deviez publier des données le premier jour. Par conséquent, vous ne saurez rien du deuxième jour. Donc, à moins que vous ne deviez vraiment, vraiment, approximer, vous feriez probablement mieux de ne pas.
Si vous l'arrondissez, il n'y a pas de bonne façon de l'obtenir de la même manière dans tous les cas.
Vous pouvez prendre la partie décimale des N pourcentages que vous avez (dans l’exemple que vous avez donné, c’est 4).
Ajoutez les parties décimales. Dans votre exemple, vous avez le total de la partie fractionnaire = 3.
Ceil les 3 nombres avec les fractions les plus élevées et sol le reste.
(Désolé pour les modifications)
Voici une implémentation Python plus simple de la réponse @ varun-vohra:
def apportion_pcts(pcts, total):
proportions = [total * (pct / 100) for pct in pcts]
apportions = [math.floor(p) for p in proportions]
remainder = total - sum(apportions)
remainders = [(i, p - math.floor(p)) for (i, p) in enumerate(proportions)]
remainders.sort(key=operator.itemgetter(1), reverse=True)
for (i, _) in itertools.cycle(remainders):
if remainder == 0:
break
else:
apportions[i] += 1
remainder -= 1
return apportions
Vous avez besoin de math
, itertools
, operator
.
J'ai mis en œuvre la méthode de la réponse de Varun Vohra ici pour les listes et les dicts.
import math
import numbers
import operator
import itertools
def round_list_percentages(number_list):
"""
Takes a list where all values are numbers that add up to 100,
and rounds them off to integers while still retaining a sum of 100.
A total value sum that rounds to 100.00 with two decimals is acceptable.
This ensures that all input where the values are calculated with [fraction]/[total]
and the sum of all fractions equal the total, should pass.
"""
# Check input
if not all(isinstance(i, numbers.Number) for i in number_list):
raise ValueError('All values of the list must be a number')
# Generate a key for each value
key_generator = itertools.count()
value_dict = {next(key_generator): value for value in number_list}
return round_dictionary_percentages(value_dict).values()
def round_dictionary_percentages(dictionary):
"""
Takes a dictionary where all values are numbers that add up to 100,
and rounds them off to integers while still retaining a sum of 100.
A total value sum that rounds to 100.00 with two decimals is acceptable.
This ensures that all input where the values are calculated with [fraction]/[total]
and the sum of all fractions equal the total, should pass.
"""
# Check input
# Only allow numbers
if not all(isinstance(i, numbers.Number) for i in dictionary.values()):
raise ValueError('All values of the dictionary must be a number')
# Make sure the sum is close enough to 100
# Round value_sum to 2 decimals to avoid floating point representation errors
value_sum = round(sum(dictionary.values()), 2)
if not value_sum == 100:
raise ValueError('The sum of the values must be 100')
# Initial floored results
# Does not add up to 100, so we need to add something
result = {key: int(math.floor(value)) for key, value in dictionary.items()}
# Remainders for each key
result_remainders = {key: value % 1 for key, value in dictionary.items()}
# Keys sorted by remainder (biggest first)
sorted_keys = [key for key, value in sorted(result_remainders.items(), key=operator.itemgetter(1), reverse=True)]
# Otherwise add missing values up to 100
# One cycle is enough, since flooring removes a max value of < 1 per item,
# i.e. this loop should always break before going through the whole list
for key in sorted_keys:
if sum(result.values()) == 100:
break
result[key] += 1
# Return
return result
vérifier si cela est valide ou non dans la mesure de mes cas de test, je suis capable de faire fonctionner cela.
disons que le nombre est k;
Ceci est un cas d'arrondi bancaire, alias «arrondi à moitié égal». Il est supporté par BigDecimal. Son but est d’assurer l’arrondi des soldes, c’est-à-dire qu’il ne favorise ni la banque ni le client.