转换变量类型(或变通方法)
Converting variable type (or workaround)
下面的类应该表示一个音符。我希望能够仅使用整数存储音符的长度(例如1/2音符,1/4音符,3/8音符等)。但是,我还希望能够使用浮点数存储长度,以便在处理不规则长度的注释时使用。
class note{
string tone;
int length_numerator;
int length_denominator;
public:
set_length(int numerator, int denominator){
length_numerator=numerator;
length_denominator=denominator;
}
set_length(double d){
length_numerator=d; // unfortunately truncates everything past decimal point
length_denominator=1;
}
}
能够使用整数而不是双精度体来存储长度对我来说很重要的原因是,在我过去使用浮点数的经验中,有时值会出乎意料地不准确。例如,一个应该是16的数字偶尔会被神秘地存储为16.0000000001或15.99999999999(通常是在经历了一些浮点运算之后),这可能会在测试相等性时导致问题(因为16!=15.99999999999)。
是否有可能将一个变量从int型转换为double型(变量,而不仅仅是它的值)?如果不是,那么根据我需要的类型,我还可以做些什么来使用整数或双精度来存储笔记的长度?
如果您唯一的问题是比较浮点数是否相等,那么我建议使用浮点数,但请先阅读"比较浮点数"/Bruce Dawson。它不长,它解释了如何正确比较两个浮点数(通过检查绝对和相对差)。
当你有更多的时间,你也应该看看"每个计算机科学家都应该知道的浮点算术"来理解为什么16偶尔会被"神秘地"存储为16.0000000001或15.99999999999。
在有理数(或定点算术)中使用整数的尝试很少像看起来那么简单。
我看到了几种可能的解决方案:第一种是使用double。这是诚然,扩展计算可能导致不准确的结果,但在在这种情况下,除数通常是2的幂,也就是正数结果(至少在我见过的所有机器上);你只会冒险当除以一些不寻常的值(也就是当你必须使用double时)。
您还可以缩放结果,例如将音符表示为64个音符的倍数。这将意味着大多数值都将是小整数,保证在double
(至少)中是精确的在通常的表示中)。一个应该是16的数字就可以不是被存储为16.000000001或15.99999999(但这是一个数字)应该是。16可能会被存储为。1600000001或。1599999999)。在long long
出现之前,十进制算术类经常出现采用double
作为52位整型,保证了在每一步实际值是一个整数。(只有除法才会产生问题。)
或者你可以使用某种表示有理数的类。(比如Boost就有一个,我相信还有其他的。)这将允许任何奇怪的值(5音符,有人吗?)保持准确;它可以也有利于人类可读的输出,例如,您可以测试分母,然后输出类似"3个四分音符"的东西,或者喜欢的。即使像"3/4音符"这样的东西对a来说也更容易读懂音乐家比"一个0.75的音符"。
不能将一个变量从int型转换为double型,但可以将一个值从int型转换为double型。我不完全确定您要的是哪个但可能您正在寻找一个并集
union DoubleOrInt
{
double d;
int i;
};
DoubleOrInt length_numerator;
DoubleOrInt length_denominator;
那么你可以写
set_length(int numerator, int denominator){
length_numerator.i=numerator;
length_denominator.i=denominator;
}
set_length(double d){
length_numerator.d=d;
length_denominator.d=1.0;
}
这种方法的问题是,你绝对必须跟踪当前在联合中存储的是整型还是双精度。如果您存储一个整型,然后试图将其作为双精度体访问,就会发生不好的事情。最好是在自己的类中进行。
这是浮点变量的正常行为。它们总是四舍五入,最后一位数字的值可能会根据您所做的操作而改变。我建议在某个地方阅读浮点数(例如http://floating-point-gui.de/) -特别是关于比较fp值。
我通常减去它们,取绝对值并将其与epsilon进行比较,例如,如果(abs(x-y)
给定您有set_length(double d)
,我的猜测是您实际上需要双元。请注意,从双精度到整数小数的转换是脆弱和复杂的,并且很可能不会解决您的等式问题(0.24999999是否等于1/4 ?)。你最好选择总是使用分数,或者总是使用双精度。然后,学习如何使用它们。我必须说,对于音乐来说,分数是有意义的,就像音符是如何被描述的一样。
如果是我,我会直接使用enum。使用这个系统将一些转换为注释也非常简单。你可以这样做:
class Note {
public:
enum Type {
// In this case, 16 represents a whole note, but it could be larger
// if demisemiquavers were used or something.
Semiquaver = 1,
Quaver = 2,
Crotchet = 4,
Minim = 8,
Semibreve = 16
};
static float GetNoteLength(const Type ¬e)
{ return static_cast<float>(note)/16.0f; }
static float TieNotes(const Type ¬e1, const Type ¬e2)
{ return GetNoteLength(note1)+GetNoteLength(note2); }
};
int main()
{
// Make a semiquaver
Note::Type sq = Note::Semiquaver;
// Make a quaver
Note::Type q = Note::Quaver;
// Dot it with the semiquaver from before
float dottedQuaver = Note::TieNotes(sq, q);
std::cout << "Semiquaver is equivalent to: " << Note::GetNoteLength(sq) << " beatsn";
std::cout << "Dotted quaver is equivalent to: " << dottedQuaver << " beatsn";
return 0;
}
你所说的那些"不规则"笔记可以使用TieNotes
检索
- 有没有什么方法可以使用一个函数中定义的常量变量,也可以由c++中同一程序中的其他函数使用
- 枚举环境变量的惯用C++14/C++17方法
- 绑定派生类方法C++从实例范围之外的分隔 std::function 变量调用
- 是否可以依赖函数范围的静态变量来执行程序关闭期间调用的方法?
- 从私有成员变量的成员方法返回unique_ptr
- 在派生类中使用基类的私有成员变量的最佳方法
- 打印所有继承的类成员变量和方法
- C++方法中的引用变量
- Visual C++: MSVC vs. GCC+CLANG: 处理 lambda 捕获类成员变量,正确的方法是什么?
- 有没有一种通用的方法来实现不变量
- 有没有将变量名称转换为双指针的简短方法?
- C++:将向量传递到构造函数以创建成员变量的最佳方法?
- C++ 互斥锁可以交叉方法/变量吗?如果是这样,为什么在这里不起作用?
- 类方法变量,如果将它们存储在类本身中会更快吗?
- 将局部方法变量分配给类指针
- 列出派生类中的所有方法/变量
- 相互冲突名称的成员变量和方法变量
- C++如果我有一个对象指针,是在堆栈或堆上分配的方法变量
- 如何从另一个类访问一个类的方法/变量,而不在c++中实例化它或子类
- 指定类变量与方法变量C++