Как отсортировать массив, который включает в себя NaN's C - PullRequest
0 голосов
/ 14 марта 2019

Я пытался реализовать мой код как средство сортировки всех целых чисел, включая NaN.Однако не могу найти функцию, которая будет сортировать NaNs в моей программе.Код может сортировать другие целые числа, включая бесконечности, однако при вводе nan программа распознает ввод, но не сортирует его до начала списка.Любая помощь будет оценена.

#include <stdio.h>
#include <math.h>

int main()
{
    float array[100], swap;
    int c, d, n;

    printf("Enter the size of array\n");
    scanf("%d", &n);

    printf("Enter %d integers\n", n);

    for (c = 0; c < n; c++)
        scanf("%f", &array[c]);

    for (c = 0; c < (n - 1); c++)
    {
        for (d = 0; d < n - c - 1; d++)
        {
            if (array[d] > array[d + 1]) 
            {
                swap = array[d];
                array[d] = array[d + 1];
                array[d + 1] = swap;
            }
        }
    }

    printf("Sorted array in ascending order:\n");


    for (c = 0; c < n; c++)
        printf("%f\n", array[c]);

    return 0;
}

Ответы [ 2 ]

1 голос
/ 14 марта 2019

Обратите внимание, что в соответствии со стандартом C два значения NaN никогда не сравниваются одинаково, даже если они имеют одинаковую битовую комбинацию.Если вы собираетесь сортировать данные с помощью NaN, вам необходимо:

  1. Решить, где следует сортировать значения NaN по правильным значениям (обычно это варианты «до отрицательной бесконечности» или «после положительной бесконечности»).
  2. Используйте гораздо более деликатные тесты, чем простое сравнение a > b.

Соответствующая информация разбросана по стандарту C11.Например:

Вы, вероятно, организуете создание функции (возможно, функции inline, если только вы не собираетесь передавать ее функции, подобной qsort()), которая сравнивает два значения с плавающей запятой соответствующего типа (выглядиткак вы используете float), который использует макрос классификации isnan() или isnanf(), чтобы определить, является ли одно или оба значения NaN.Функция, вероятно, вернет значение, указывающее равенство, если оба значения являются NaN, но если одно является NaN, возвращаемое значение поместит его раньше или позже другого, в зависимости от порядка, в котором вы хотите, чтобы NaN появлялись, и вернет значение.соответствующее значение для сравнения других значений (нормальные значения, нули, бесконечности, субнормальные числа) - для регулярных значений и бесконечностей требуются только операторы регулярного сравнения, если только вам не нужно правильно сортировать отрицательные нули по положительным нулям.

ДляНапример, написание функции, которая работает с qsort() (и с использованием типа double вместо float), приводит к чему-то вроде этого, предполагая, что числа должны быть отсортированы в порядке возрастания и что NaN должны сравниваться меньше, чем любое другое значение.Код включает тестовый код для считывания данных со стандартного ввода, распечатки, сортировки и повторной печати. ​​

#include <math.h>

/* Belongs in a header! */
extern int cmp_double(const void *v1, const void *v2);

/* Sort doubles, with NaNs coming first */
/* Switch return values -1 and +1 after testing n1, n2 to sort NaNs last */
int cmp_double(const void *v1, const void *v2)
{
    double d1 = *(const double *)v1;
    double d2 = *(const double *)v2;
    int n1 = isnan(d1);
    int n2 = isnan(d2);

    if (n1 && n2)
        return 0;
    if (n1)
        return -1;
    if (n2)
        return +1;
    if (d1 < d2)
        return -1;
    if (d1 > d2)
        return +1;
    // The values are 'equal', but …
    if (d1 != 0.0)
        return 0;
    // They're both zero, but they could have different signs
    int s1 = signbit(d1);
    int s2 = signbit(d2);
    if (s1 != s2)
        return (s1) ? -1 : +1;
    return 0;
}

#include <stdio.h>
#include <stdlib.h>

static void dump_doubles(const char *tag, int num, double values[num])
{
    printf("%s (%d):\n", tag, num);
    int line_len = 0;
    for (int i = 0; i < num; i++)
    {
        int n = printf(" %+12.4f", values[i]);
        if (n <= 0)
            break;
        line_len += n;
        if (line_len >= 60)
        {
            line_len = 0;
            putchar('\n');
        }
    }
    if (line_len > 0)
        putchar('\n');
}

int main(void)
{
    enum { NUM_VALUES = 50 };
    double values[NUM_VALUES];

    int i = 0;

    for (i = 0; i < NUM_VALUES; i++)
    {
        if (scanf("%lf", &values[i]) != 1)
            break;
    }

    dump_doubles("Before sort", i, values);
    qsort(values, i, sizeof(values[0]), cmp_double);
    dump_doubles("After sort", i, values);

    return 0;
}

Обратите внимание на тестирование, необходимое для сортировки -0.0 до +0.0!

Рассмотрим входные данные:

3023.421800 9033.902200 nan -9370.952500 3088.884900 6829.135400 0
-0.000000 -inf -5267.546800 -8784.373300 5663.944600 -9728.231300 inf
-inf -5373.038600 4282.941600 6245.734200 -5533.975400 nan 8445.713600
+inf -9108.960400 -3796.671200 nan -2363.851300 877.460400 9936.416900
-3480.867400

Выходные данные:

Before sort (29):
   +3023.4218   +9033.9022          nan   -9370.9525   +3088.8849
   +6829.1354      +0.0000      -0.0000         -inf   -5267.5468
   -8784.3733   +5663.9446   -9728.2313         +inf         -inf
   -5373.0386   +4282.9416   +6245.7342   -5533.9754          nan
   +8445.7136         +inf   -9108.9604   -3796.6712          nan
   -2363.8513    +877.4604   +9936.4169   -3480.8674
After sort (29):
          nan          nan          nan         -inf         -inf
   -9728.2313   -9370.9525   -9108.9604   -8784.3733   -5533.9754
   -5373.0386   -5267.5468   -3796.6712   -3480.8674   -2363.8513
      -0.0000      +0.0000    +877.4604   +3023.4218   +3088.8849
   +4282.9416   +5663.9446   +6245.7342   +6829.1354   +8445.7136
   +9033.9022   +9936.4169         +inf         +inf
0 голосов
/ 14 марта 2019

Как уже упоминалось в комментариях, ваш код является кодом C, а не C ++.Вот ваш код на C ++ с дополнительным условием, которое должно решить вашу проблему:

#include <iostream>
#include <vector>
#include <cmath>

int main()
{
    std::size_t array_size;
    std::cout << "Enter the size of array\n";
    std::cin >> array_size;

    std::cout << "Enter " << array_size << " integers\n";

    std::vector<float> array(array_size);
    for(std::size_t i = 0; i < array.size(); ++i)
        std::cin >> array[i];

    for(std::size_t a = 0; a < array.size() - 1; ++a)
        for(std::size_t b = 0; b < array.size() - 1 - a; ++b)
            if(std::isnan(array[b + 1]) || array[b] > array[b + 1])
                std::swap(array[b], array[b + 1]);

    std::cout << "Sorted array in ascending order:\n";

    for(const auto& a : array)
        std::cout <<  a << '\n';

    return 0;
}

И если вы не хотите писать все вещи сортировки самостоятельно, вы можете сделать это с еще большим количеством C ++ ибиблиотека алгоритмов (и дополнительная проверка ввода):

template<typename T>
T get_input()
{
    T input;
    while(true)
    {
        std::cin >> input;
        if(std::cin)
            return input;
        std::cin.clear();
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        std::cout << "Invalid input! Please try again.\n";
    }
}

int main()
{
    std::cout << "Enter the size of array\n";
    std::size_t array_size = get_input<std::size_t>();

    std::cout << "Enter " << array_size << " integers\n";

    std::vector<float> input(array_size);
    for(auto& a : input)
        a = get_input<float>();

    std::sort(input.begin(), input.end(), [](const auto& a, const auto& b){ return std::isnan(a) || a < b; });

    std::cout << "Sorted array in ascending order:\n";

    for(const auto& a : input)
        std::cout << a << '\n';
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...