来自cmath的函数生成运行时无限循环(没有这样的文件或目录)

Functions from cmath generate run-time infinite loop (No such file or directory)

本文关键字:文件 函数 cmath 运行时 来自 无限循环      更新时间:2023-10-16

我正在为类编写一个程序,该程序从文件中读取一组有序对,并实现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::xValnode::yVal是双精度的,或者通过比较整数来固定不相等的比较,或者通过适当地比较浮点数来固定不等于的比较,那么程序可能不会无限循环(对于我尝试的输入,它不会无限循环(。

请注意,使用标志-Wconversion时,会出现针对centerList[i].xVal = average;centerList[i].yVal = average;的警告。此外,-Wconversion不被-Wall-Wextra覆盖。我发现,在为数值算法开发代码时,-Wconversion是一个值得使用的标志,尽管它可能会产生许多看似温和的警告。一切都很好,直到从floatint的破坏性隐式转换导致了巨大的相对误差。

我假设当您插入断点时,gdb指示sqrt,因为centerList[i].xVal = average;0相对昂贵且调用频繁。gdb根本找不到sqrt的源代码(可能是因为您的系统上没有安装该源代码(。

sqrt无关。我看到的唯一一个无限循环是proceed不断地变成true。这反过来又是因为将替身与平等进行比较充其量是可疑的。

这可能是由于实现错误(我不擅长集群来查找它们(;这很可能是由于舍入误差。

由于您已经使用了调试器,请逐步完成while(proceed)循环并查看average的行为。根据它的不同,您需要重新访问算法,或者在比较时允许容差。