简体   繁体   English

使用浮点数和整数

[英]Working With Floats and Integers

I've created an ATM like program which holds the money in a person's account. 我已经创建了一个ATM程序,它将钱存入一个人的账户。 When the person takes out a withdrawal, it subtracts the withdrawal from the account along with a .50 surcharge. 当该人取出提款时,它会从账户中扣除50%的附加费。 The problem I'm having is working with both integers and floats in this program. 我遇到的问题是在这个程序中使用整数和浮点数。 I converted the integer account to a floating point number but I get an error message when I try to print out the statement. 我将整数帐户转换为浮点数,但是当我尝试打印语句时收到错误消息。 Can someone tell me what I'm doing wrong? 有人能告诉我我做错了什么吗?

#include <stdio.h>

int main (void) {
    int account = 2000;
    int withdrawal;
    float charge = 0.50;

    printf ("How much money would you like to take out? ");
    scanf ("%i", &withdrawal);

    while (withdrawal % 5 != 0) {
        printf ("Withdrawal must be divisible by 5. ");
        scanf("%i", &withdrawal);
    }

    account = ((float) account - charge) - withdrawal;

    printf("Remaining account: %.2f\n", account);

    return 0;
}
int account = 2000;
printf("Remaining account: %.2f\n", account);

This is wrong; 这是错的; it should be "%d" for integer, or better, change your account variable type to something that could represent the 0.50 you're surcharging. 对于整数,它应该是"%d" ,或者更好,将您的account变量类型更改为可能代表您正在充电的0.50。 I don't recommend you to using (imprecise) float s for money either. 我不建议您使用(不精确) float钱。 You don't want to withdraw 10.499999997 when you meant 10.5 . 当你的意思是10.5时,你不想撤销10.499999997 You need to think about the precision and rounding rules you'd use. 您需要考虑您使用的精度和舍入规则。 AFAIK these are both mandated by laws or something. AFAIK这些都是法律规定的。

You simply cannot use floating-point values to represent currency, since they have the wrong properties. 您根本无法使用浮点值来表示货币,因为它们具有错误的属性。 Not all numbers are exactly representable, so you will have "mysterious" effects. 并非所有数字都可以完全表示,因此您将拥有“神秘”效果。

It's better to use a "fixed-point" approach, the easiest is to take a largeish integer type such as long and then just multiplying it by an integer, typically 100 if all you need are whole cents (for US currency). 最好使用“定点”方法,最简单的方法是采用一个大的整数类型,例如long ,然后将它乘以一个整数,通常为100,如果您只需要全部美分(美元)。 If you need fractions of cents, multiply by more such as 10,000 to be able to represent all values down to 1/100:th of one cent. 如果你需要分数的分数,乘以更多,如10,000,以便能够代表所有值低至1/100:百分之一。

With this scheme, $1 would be: 有了这个计划,$ 1将是:

long one_dollar = 1 * 10000;

And 13 cents would be: 13美分将是:

long thirteen_cents = 13 * 100;

Note that this in turn limits how large amounts of money you can represent. 请注意,这反过来限制了您可以代表的大笔金额。 Eventually, you may find you need an arbitrary-precision library to get "unlimited"-precision integers. 最终,您可能会发现需要一个任意精度的库来获得“无限制”的精度整数。

Please , do not use floats when handling money. 不要在处理钱时使用花车。 Use an integer type, as to track cents, and then convert that at output to dollars and cents (or whatever currency). 使用整数类型,以跟踪美分,然后将输出转换为美元和美分(或任何货币)。

In particular, 0.1 decimal does not have an exact floating point representation. 特别是,0.1 十进制没有精确的浮点表示。 Instead, it is represented as an endless repeating binary fraction (0.19999999999.... hex ). 相反,它表示为无穷无尽的重复二进制分数(0.19999999999 ...... hex )。 Likewise, 0.01 decimal is approximately 0.028F5C28F... hex . 同样,0.01 十进制约为0.028F5C28F ... 十六进制

让你的生活变得更轻松,而不是把你的“in”视为美元,把它们想象成“美分”,那么你就不需要浮点数了。

The warning you see is due to the fact that you pass an int to printf() having given it %.2f as the format string. 您看到的警告是由于您将一个int传递给printf() ,并将%.2f 。。 %.2f作为格式字符串。 This format string is to be used for floating point numbers. 此格式字符串用于浮点数。 See printf . printf

There is a more fundamental flaw in the code, however. 但是,代码中存在更为根本的缺陷。 You should not use floating point variables to represent numbers when exact decimal fractions are required, in particular when working with monetary amounts. 当需要精确的小数部分时,不应使用浮点变量来表示数字,特别是在使用货币金额时。 In short, the reason not to use floating point numbers in your application is that decimal fractions cannot be represented exactly. 简而言之,在您的应用程序中不使用浮点数的原因是小数分数无法准确表示。 In every positional number system some numbers are represented by an infinite repeating sequence. 在每个位置编号系统中,一些数字由无限重复序列表示。 For example, 例如,

in decimal system 1/3 is represented as 0.33[3] 在十进制系统1/3中表示为0.33 [3]

(square brackets indicating infinitely repeating sequence of digits). (方括号表示无限重复的数字序列)。 Similarly, in binary some numbers require infinite sequence of 0s and 1s to be represented. 类似地,在二进制中,一些数字需要表示0和1的无限序列。 For example, 例如,

in binary system, 1/10 is 0.000110011[0011] 在二进制系统中,1/10是0.000110011 [0011]。

Since registers and memory locations are finite in length this is rounded up or down and represents a number slightly above or below 0.1. 由于寄存器和存储器位置的长度是有限的,因此向上或向下取整并表示略高于或低于0.1的数字。 Thus, you cannot store the exact value 0.1 in a float or double . 因此,您不能将精确值0.1存储在floatdouble

For more details, see What Every Computer Scientist Should Know About Floating-Point Arithmetic . 有关更多详细信息,请参阅每个计算机科学家应该知道的关于浮点运算的内容

One alternative is for example to use integer variables representing cents. 一种替代方案是例如使用表示美分的整数变量。

你打印帐户好像它是一个浮点数( %2f ),即使它是一个整数,你应该使用%d格式说明符代替

You should probably use Binary Coded Decimals when dealing with money. 你应该在处理钱时使用二进制编码的小数。 It will allow you to use a single variable for both dollars and cents. 它允许您使用单个变量来计算美元和美分。 While you are at it, you can specify a typedef struct union that will let you specify the value in dollars, cents, whole dollars only, and cents remainder only. 在您使用它时,您可以指定一个typedef结构联合,它允许您以美元,美分,仅美元和仅剩余分数来指定值。 Short of exchange with other currencies, that will be good for just about every monetary scenario. 与其他货币交易不足,这对几乎每种货币情况都有好处。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM