Изменения значений с плавающей точкой. Не уверен почему - PullRequest
0 голосов
/ 14 декабря 2011

У меня есть два файла.

  • TreeSearch.cpp
  • TreeSearchCUDA.cu

В TreeSearch.cpp у меня есть:

int* searchTree(vector<TreeNode> &tree, vector<ImageFeature> featureList)
{
    float** features = makeMatrix(featureList, CHILDREN);
    float* featuresArray = makeArray(features, featureList.size());
    float* centroidNodes = convertTree(tree);

    int numFeatures = featureList.size();
    for(int j = 0; j < 10; j++)
    {
        cout << "C++ " << centroidNodes[j] << endl;
    }
    cout << "" << endl;

    int* votes = startSearch(centroidNodes, tree.size(), featuresArray, numFeatures);

    return votes;
}

startSearch существует в TreeSearchCUDA.cu, который выглядит так:

int* startSearch(float* centroids, int nodesCount, float* features, int featuresCount)
{
    for(int j = 0; j < 10; j++)
    {
        printf("CUDA %f \n", centroids[j]);
    }
    ...
}

Теперь, если мы посмотрим на вывод, он будет выглядеть так:

C++ 0
C++ 2.52435e-29
C++ 0
C++ 2.52435e-29
C++ 6.72623e-44
C++ 1.26117e-44
C++ 2.03982e+12
C++ 4.58477e-41
C++ 0
C++ 1.26117e-44

CUDA 0.000000 
CUDA 0.000000 
CUDA 0.000000 
CUDA 0.000000 
CUDA 0.000000 
CUDA 0.000000 
CUDA 2039820058624.000000 
CUDA 0.000000 
CUDA 0.000000 
CUDA 0.000000 

Результаты не совпадают.У кого-нибудь есть какие-либо идеи?:) У меня есть идея, потому что некоторые части кода скомпилированы с -m64, а некоторые нет.Однако изменить это невозможно.При связывании объектов я использую -m64.

Я надеюсь, у кого-то есть решение или объяснение:)

Ответы [ 3 ]

2 голосов
/ 14 декабря 2011

Из ваших выводов видно, что CUDA приближает действительно маленькие значения с плавающей точкой к 0.Все ваши входные данные являются действительно небольшими числами с плавающей запятой или 0, за исключением 2.03982e+12.2.03982e+12 остается неизменным на выходе.Ваши центроиды должны быть очень маленькими?

1 голос
/ 14 декабря 2011

float s не являются точными, вы можете использовать заголовок <limits>, чтобы получить информацию о том, сколько цифр в вашем (десятичном) числе можно безопасно использовать и которые гарантированно останутся неизменными.

 #include <limits>

 ...

 std::cerr << std::numeric_limits<float>::digits10 << std::endl;

В моей системе это выдает 6, что означает, что я могу быть уверен, что число с плавающей точкой будет точным при использовании до 6 десятичных знаков.Но число, состоящее из большего числа десятичных дробей, не считается точным, numeric_limits<float> не гарантирует, что эти числа останутся неизменными и останутся на 100% неизменными.

Еще одна вещь, которую я мог бы добавить, заключается в том, что printf не делает• печатая числа с плавающей запятой, как это делает std::ostream, часто существует внутренняя разница в том, как обрабатываются и печатаются числа с плавающей запятой.Я не думаю, что printf с %f по умолчанию "доверяет" столько десятичных знаков, сколько std::ostream в научном представлении.


#include <limits>
#include <iostream>

int
main (int argc, char *argv[])
{
  float x = 0.1234599999; // 10 digits

  std::cout.precision (10);
  std::cout << x << std::endl;
}

вывод (в моей системе)

0.1234600022
0 голосов
/ 14 декабря 2011

Согласно http://developer.download.nvidia.com/assets/cuda/files/NVIDIA-CUDA-Floating-Point.pdf, в «Устройствах с вычислительной возможностью 1.2» [или 1.3 для чисел с плавающей запятой], «Денормальные числа (небольшие числа, близкие к нулю) сбрасываются в ноль».Денормальные числа - это числа между ~ 1.4e-45 и ~ 1.18e-38 (http://en.wikipedia.org/wiki/Single-precision_floating-point_format),, поэтому это объясняет, как ваши e-41 и e-44 оказались в 0. Я не уверен насчет e-29, но могло произойти нечто подобное.

...