两个一般的CS问题 [英] Two General CS Questions

查看:166
本文介绍了两个一般的CS问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当比较两个真实数字的相等性时,为什么我不应该使用==运算符,而应该使用什么代替?



coersion和cast之间有什么区别?这是我一般的假设,当你强制一个值为另一种类型,像这样强制转换:

  int n = 9; 
return double(n)/ 5;


解决方案


使用==运算符?


,因为它可能不工作。但是不是 == 运算符是一个问题。问题是数字本身。一些浮点数不具有精确的二进制表示,并且浮点数学不是精确的。例如,如 0.2 的简单值不能使用二进制浮点数精确表示,浮点数的精度有限意味着操作顺序的轻微变化可能会改变结果。不同的编译器和CPU架构会以不同的精度存储临时结果,因此结果会因您的环境细节而异。



如果进行计算,对于一些预期值,结果非常不可能得到您想要的结果。



换句话说,如果你做一个计算,然后做这个比较:

  if(result == expectedResult)

那么比较不太可能是真的。如果比较是真的,那么它可能是不稳定的 - 输入值,编译器或CPU的微小变化可能会改变结果,并使比较结果为假。



浮点数取决于上下文。因为即使改变操作的顺序可以产生不同的结果,重要的是知道如何等于你想要的数字。这被称为 epsilon



有多种注意事项:




  • 在比较的值中,已经错误的容忍度是多少?

  • H0:是

    可以接受比较报告为true吗?

  • H1:对于确切值相等的情况,比较报告为false,
    是否可接受?



混淆和错误的根源是正在比较的数字本身,而不是比较。事实上 == 运算符是可靠的 - 它总是返回正确的答案取实际参数。



比较浮点数由布鲁斯道森是一个很好的起点,当看浮点比较。

每个程序员应该知道的浮点运算是另一个很好的文章

以下定义来自 Knuth的计算机编程艺术

  bool aboutEqual(float a,float b,float epsilon)
{
return fabs(a-b)< =((fabs(a) (b)? fabs(b):fabs(a))* epsilon);
}

bool essentiallyEqual(float a,float b,float epsilon)
{
return fabs(a-b)< =((fabs > fabs(b)?fabs(b):fabs(a))* epsilon)。
}

bool definitelyGreaterThan(float a,float b,float epsilon)
{
return(a-b)> ((fabs(a)< fabs(b)?fabs(b):fabs(a))* epsilon)
}

bool definitelyLessThan(float a,float b,float epsilon)
{
return(b - a)> ((fabs(a)< fabs(b)?fabs(b):fabs(a))* epsilon)
}

选择epsilon取决于上下文,是。






强制



当你没有明确指定它(直接)。它是自动的

  double f(int i){
return i;
}< - coersion int double double

double d;
long l;
int i;

if(d> i)d = i; //< -coersion
if(i> l)l = i; //< -coersion
if(d == l)d * = 2; //< -coersion



铸造



你明确使用它,你说

  static_cast<>()
dynamic_cast< $ b const_cast<>()
reinterpret_cast<>()

这些具有不同的,专门的意义,即 dynamic_cast 适用于多态类型,并且类型安全,所以你使用它来转换 Base * 指针(或基本和引用)到 Derived * (或Derived&)安全 - 测试实际对象是否正确期待它成为。 dynamic_cast 的目标不必是多态的 - 这允许一种特殊类型的传输(将具体对象封装在多态类型中,然后再次打开到具体对象。 Bjarne Stroustrup C ++ ...,15.4.1 Dynamic_cast,p。408])。 reinterpret_cast 用于指针转换,指针不必指向多态类型(即具有虚函数的类), static_cast 不检查类型在运行时 - 因此它不介绍一点,开销有关 dynamic_cast 它必须检查 type_info 与被转换的对象相关联。



但是只有 static_cast 可能会从 void * 它不需要关于指向的内存的附加信息。还非常重要的是 static_cast 失败会导致运行时错误,但 dynamic_cast 将返回 0 用于指针或引用 bad_cast 异常。 const_cast 是自我说明, 需要:您无法使用 dynamic_cast code>或 static_cast ,所以说它们都尊重constness。他们都尊重访问控制(也不可能转换到私有基础[因为只有派生类方法可能会 Derived * - > Base * 和类的方法是朋友的{friend声明在Base}])


When comparing two "real" numbers for equality, why should I not use the == operator, and what should I use instead?

What is the difference between coersion and casting? It is my general assumption that casting is when you force a value to be of another type like so:

int n = 9;
return double(n)/5;

解决方案

why should I not use the == operator?

because it might not work. But it is not the == operator that is a problem. The problem are numbers itself. Some of floating point numbers don't have exact binary representation and floating point math is not exact. For example simple values like 0.2 cannot be precisely represented using binary floating point numbers, and the limited precision of floating point numbers means that slight changes in the order of operations can change the result. Different compilers and CPU architectures store temporary results at different precisions, so results will differ depending on the details of your environment.

If you do a calculation and then compare the results against some expected value it is highly unlikely that you will get exactly the result you intended.

In other words, if you do a calculation and then do this comparison:

if (result == expectedResult)

then it is unlikely that the comparison will be true. If the comparison is true then it is probably unstable – tiny changes in the input values, compiler, or CPU may change the result and make the comparison be false.

Therefore comparing floating point numbers depends on the context. Since even changing the order of operations can produce different results, it is important to know how "equal" you want the numbers to be. This is called epsilon.

There are multiple things to consider:

  • What is your tolerance for errors already present in the values being compared?
  • H0: For what cases in which the exact values would differ is it
    acceptable that the comparison report true?
  • H1: For what cases in which the exact values would be equal is it acceptable that the comparison report false?

The source of confusion and error are the numbers itself that are being compared, not the comparison. In fact == operator is reliable - it always returns correct answer taking actual arguments.

Comparing floating point numbers by Bruce Dawson is a good place to start when looking at floating point comparison.
What Every Programmer Should Know About Floating-Point Arithmetic is another very nice article.

Rule of thumb.

The following definitions are from The art of computer programming by Knuth:

bool approximatelyEqual(float a, float b, float epsilon)
{
    return fabs(a - b) <= ( (fabs(a) < fabs(b) ? fabs(b) : fabs(a)) * epsilon);
}

bool essentiallyEqual(float a, float b, float epsilon)
{
    return fabs(a - b) <= ( (fabs(a) > fabs(b) ? fabs(b) : fabs(a)) * epsilon);
}

bool definitelyGreaterThan(float a, float b, float epsilon)
{
    return (a - b) > ( (fabs(a) < fabs(b) ? fabs(b) : fabs(a)) * epsilon);
}

bool definitelyLessThan(float a, float b, float epsilon)
{
    return (b - a) > ( (fabs(a) < fabs(b) ? fabs(b) : fabs(a)) * epsilon);
}

Choosing epsilon depends on the context, and determines how equal you want the numbers to be.


Coercion

it is implicit cast, so happens there when you not specify it explicitly (directly). It is automatic

    double f(int i){ 
    return i;
    } <- coersion int to double

double  d;
long    l;
int     i;

if (d > i)   d = i; // <-coersion
if (i > l)   l = i; // <-coersion
if (d == l)  d *= 2; // <-coersion

Casting

you use it explicitly, you say

static_cast<>()
dynamic_cast<>()
const_cast<>()
reinterpret_cast<>()

and each of these has different, specialized meaning, i.e dynamic_cast is appropriate for polymorphic types, and type safe, so you use it to convert Base* pointer (or Base& reference) to Derived* (or Derived&) safely - testing if the actual object is exactly what you are expecting it to be. Target of dynamic_cast doesn't have to be polymorphic - this allows for a special type of transmission (wrap concrete object in a polymorphic type and then unwrap to concrete again later, [see Bjarne Stroustrup C++..., 15.4.1 Dynamic_cast, p. 408]). reinterpret_cast is used for pointers conversion and pointers don't have to point to polymorphic type (that is class with virtual function), static_cast doesn't examine type in runtime - so it doesn't introduce a little, little overhead related to dynamic_cast which has to check type_info associated with an object being casted.

However only static_cast might cast from void* because it doesn't need additional information about memory being pointed to. Also very important is that static_cast failure results in run time error but dynamic_cast will return 0 for pointer or throw bad_cast exception in case of references being casted. const_cast is self explanatory, and is needed: you cannot cast constness with dynamic_cast or static_cast, so it is said that they both respect constness. They both respect access controls also (it is not possible to cast to a private base [because only derived class methods might do Derived* -> Base* and methods of classes being friends to this {friend declaration is in Base}])

这篇关于两个一般的CS问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆