来自cmath的函数生成运行时无限循环(没有这样的文件或目录)
Functions from cmath generate run-time infinite loop (No such file or directory)
我正在为类编写一个程序,该程序从文件中读取一组有序对,并实现k-means算法来识别数据簇。这涉及到距离公式的使用,该公式需要计算平方根。因此,我包含了cmath库,并使用了sqrt((函数,所有内容都能正确编译。然而,在运行时,该程序会生成一个无限循环,我在gdb中确定这是由于使用sqrt函数引起的,这会导致gdb生成行"w_sqrt.c:没有这样的文件或目录"。cstdlib库中的rand((函数也有类似的未解决问题,但在解决sqrt((问题之前,我无法复制它。
注意:这是我第一次在StackOverflow上发布问题,所以如果我忽略了在这里发布的任何惯例或规则,我提前道歉。
附加说明:请将反馈限制为与我上面描述的问题直接相关的反馈。出于学术诚实的原因,我并没有就k均值函数的实现寻求建议,我只是想让程序运行起来,这样,如果有进一步的问题,我可以自己识别并解决。
提前谢谢。
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <cmath>
using namespace std;
const int ARRAY_MAX = 1000;
//DECIMAL_MULT = 10^(required number of decimal places)
const int DECIMAL_MULT = 10000;
struct node{
double xVal;
double yVal;
char symbol;
int clusterIndex;
};
//Returns the distance between the two input nodes
double getDistance(node A, node B) {
double xSquare = ((B.xVal - A.xVal) * (B.xVal - A.xVal));
double ySquare = ((B.yVal - A.yVal) * (B.yVal - A.yVal));
double result = sqrt(xSquare + ySquare);
return result;
}
int main(){
int numNodes = 0;
char temp[ARRAY_MAX];
string filename;
ifstream file;
cout << "Enter the name of the file to be read: ";
getline(cin, filename);
file.open(filename.c_str());
//Check the number of data entries present in the file
while (!(file.eof())) {
numNodes++;
file.getline(temp, ARRAY_MAX);
}
numNodes--;
file.close();
node list[numNodes];
file.open(filename.c_str());
//Build a list of data points
double xMin, xMax, yMin, yMax;
double value;
file >> value;
file.ignore();
xMin = value;
xMax = value;
list[0].xVal = value;
file >> value;
file.ignore();
yMin = value;
yMax = value;
list[0].yVal = value;
for (int i = 1; i < numNodes; i++) {
file >> value;
file.ignore();
list[i].xVal = value;
if (value < xMin) (xMin = value);
if (value > xMax) (xMax = value);
file >> value;
file.ignore();
list[i].yVal = value;
if (value < yMin) (yMin = value);
if (value > yMax) (yMax = value);
}
//Prompt user for number of clusters and symbol to be used for each
int numClusters;
cout << "Please enter the number of clusters to be analyzed: ";
cin >> numClusters;
cin.ignore();
node centerList[numClusters];
char usedSymbols[numClusters];
char entry;
bool validEntry;
for (int i = 0; i < numClusters; i++) {
centerList[i].clusterIndex = i;
do {
validEntry = true;
cout << "Please enter the character representing "
<< "cluster " << i + 1 << ": ";
cin >> entry;
cin.ignore();
for (int j = 0; j < i; j++) {
if (centerList[j].symbol == entry){
cout << "Character has already been "
<< "used.n";
validEntry = false;
break;
}
}
} while (!validEntry);
centerList[i].symbol = entry;
}
//Assign random starting points to cluster centers
srand(time(NULL));
int xMaxCast = xMax * DECIMAL_MULT;
int xMinCast = xMin * DECIMAL_MULT;
int yMaxCast = yMax * DECIMAL_MULT;
int yMinCast = yMin * DECIMAL_MULT;
int xRange = xMaxCast - xMinCast;
int yRange = yMaxCast - yMinCast;
int randValue;
for (int i = 0; i < numClusters; i++) {
randValue = std::rand() % xRange + xMinCast;
centerList[i].xVal = randValue / DECIMAL_MULT;
randValue = std::rand() % yRange + yMinCast;
centerList[i].yVal = randValue / DECIMAL_MULT;
}
//Determine the cluster of each node
for (int i = 0; i < numNodes; i++) {
list[i].clusterIndex = centerList[0].clusterIndex;
for (int j = 1; j < numClusters; j++) {
if (getDistance(list[i], centerList[list[i].clusterIndex])
> getDistance(list[i], centerList[j])) {
list[i].clusterIndex = j;
}
}
list[i].symbol = centerList[list[i].clusterIndex].symbol;
}
bool proceed = true;
double average;
int clusterCount;
while (proceed) {
proceed = false;
//Move each cluster center to the centroid of its currently
// assigned points; if all centers are already in the
// correct positions, discontinue this operation
for (int i = 0; i < numClusters; i++) {
average = 0;
clusterCount = 0;
for (int j = 0; j < numNodes; j++) {
if (list[j].clusterIndex == i) {
average += list[j].xVal;
clusterCount++;
}
}
average /= clusterCount;
if (centerList[i].xVal != average) {
proceed = true;
centerList[i].xVal = average;
}
average = 0;
clusterCount = 0;
for (int j = 0; j < numNodes; j++) {
if (list[j].clusterIndex == i) {
average += list[j].yVal;
clusterCount++;
}
}
average /= clusterCount;
if (centerList[i].yVal != average) {
proceed = true;
centerList[i].yVal = average;
}
}
if (proceed) {
//Update cluster assignment of each node
for (int i = 0; i < numNodes; i++) {
for (int j = 0; j < numClusters; j++) {
if (getDistance(list[i],
centerList[list[i].clusterIndex])
> getDistance(list[i],
centerList[j])) {
list[i].clusterIndex = j;
}
}
list[i].symbol =
centerList[list[i].clusterIndex].symbol;
}
}
}
}
请注意,在像centerList[i].xVal != average
这样的表达式中(即,int不等于double(,两个值将作为double进行比较。这最终成为比较浮点数的一种糟糕方法,这一点被广泛讨论。
但真正的问题发生在这里。CCD_ 2不将centerList[i].xVal
分配给average
,而是将(int) average
(与average
最接近的整数(分配给零。这导致了一种无限重复的情况。如果node::xVal
和node::yVal
是双精度的,或者通过比较整数来固定不相等的比较,或者通过适当地比较浮点数来固定不等于的比较,那么程序可能不会无限循环(对于我尝试的输入,它不会无限循环(。
请注意,使用标志-Wconversion
时,会出现针对centerList[i].xVal = average;
和centerList[i].yVal = average;
的警告。此外,-Wconversion
不被-Wall
或-Wextra
覆盖。我发现,在为数值算法开发代码时,-Wconversion
是一个值得使用的标志,尽管它可能会产生许多看似温和的警告。一切都很好,直到从float
到int
的破坏性隐式转换导致了巨大的相对误差。
我假设当您插入断点时,gdb
指示sqrt
,因为centerList[i].xVal = average;
0相对昂贵且调用频繁。gdb
根本找不到sqrt
的源代码(可能是因为您的系统上没有安装该源代码(。
与sqrt
无关。我看到的唯一一个无限循环是proceed
不断地变成true
。这反过来又是因为将替身与平等进行比较充其量是可疑的。
这可能是由于实现错误(我不擅长集群来查找它们(;这很可能是由于舍入误差。
由于您已经使用了调试器,请逐步完成while(proceed)
循环并查看average
的行为。根据它的不同,您需要重新访问算法,或者在比较时允许容差。
- C++ gmock - 我们如何在单元测试 cpp 文件中读取/获取 cpp 文件函数的参数值
- 使用其他头文件函数的头文件
- 创建文件函数是否可以打开仅在WinObj实用程序中的全局目录下列出的设备的句柄?
- 如何指定创建文件函数获取未缓存的结果?
- 标准库头文件函数原型的实现是如何用 c++ 编写的?
- 如何将类对象作为对另一个头文件函数的引用传递
- 读取文件函数lpbuffer和字节以读取澄清
- C++ - 未定义的对多个文件函数的引用
- 使用C++的可视 Unicode 文件函数
- C 创建文件函数错误
- WinAPI 创建文件函数 2.
- 具有CREATE_ALWAYS处置的创建文件函数
- 重写c库文件函数
- 如何使用客户端调用堆栈中的地址从 PDB 检索文件/函数/行号?
- 通过头文件函数将遍历的数据从二进制搜索树加载到Vector中
- 需要帮助无法弄清楚为什么我的头文件函数声明不起作用
- 是否可以在不使用文件函数的情况下使用代码块从文件运行某些用例测试?
- 如何用c++文件函数读写8位整数单位形式的数据
- 在c++中读文件函数如何识别文本文件的结束
- 使用Windows API的c++文件函数