Разный вывод в VisualStudio и Codeblocks

Мне нужна линейная интерполяция в 2D-массиве. Вывод в Codeblocks правильный, а в VisualStudio — нет.

У меня есть 2 основные функции.

  1. Линейная интерполяция в 1D-массиве: Функция — Y(X), а результат — Y(x).

  2. Линейная интерполяция в 2D-массиве: Функция — Y(X1, X2), а результат — Y(x, y).

И функция, чтобы проверить это.

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

double lin_int(int size, double* X, const double* Y, double x){
    int i;
    if (x >= *(X + size-1)){
        return *(Y + size-1);
    } else
    if (x <= *(X)){
        return *(Y);
    }
    for(i = 1; i < size; i++){
        if (*(X + i) >= x && *(X + i - 1) <= x){
            if (*(X+i) == *(X+i-1)){
                return *(Y + i - 1)+(*(Y + i)-*(Y + i - 1))*(x-*(X+i-1))/(*(X+i-1)*2); //два совпадающих значения в узлах (деление на ноль)
            }
            return *(Y + i - 1)+(*(Y + i)-*(Y + i - 1))*(x-*(X+i-1))/(*(X+i)-*(X+i-1));
        }
    }
}

/*
             |       X2[j]           y              X2[j+1]
_____________|_____________________________________________________________
X1[i]        |      Y[i][j]          x1            Y[i][j+1]
             |
x            |                     return
             |
X1[i+1]      |     Y[i+1][j]         x2           Y[i+1][j+1]
             |
X1[m]
X2[n]
Y[m][n]
*/
double lin_int_for_mass(int m, int n, double* X1, double* X2, const double* Y, double x, double y){
    int i;
    int j;
    double x1, x2;
    bool in_X1, in_X2;                                  //Проверки, что искомая точка за границей:
    if (x < *(X1) && y < *(X2)) return *Y;              //по X1 и X2 меньше оба значения x, y - возвращаем Y[0][0]
    if (x > *(X1+m) && y > *(X2+n)) return *(Y+m*n-1);  //по X1 и X2 больше оба значения x, y - возвращаем Y[m][n]
    if (x < *(X1)) x = *(X1);                           //по X1 значение x меньше X1[0] - ставим x = X1[0]
    if (y < *(X2)) y = *(X2);                           //по X2 значение y меньше X2[0] - ставим y = X2[0]
    if (x > *(X1+m-1)) x = *(X1+m-1);                   //по X1 значение x больше X1[m] - ставим x = X1[m]
    if (y > *(X2+n-1)) y = *(X2+n-1);                   //по X2 значение y больше X2[n] - ставим y = X2[n]
    for (i = 0; i < n-1; i++){
        if (x == *(X1 + i)){ //Проверка что мы в узле X1
            in_X1 = true;
            break;
        } else
        if (x > *(X1 + i) && x < *(X1 + i + 1)) break; //Если не в узле, фиксируем индекс предыдущего узла
    }
    for (j = 0; j < m-1; j++){
        if (y == *(X2 + j)){ //Проверка что мы в узле X2
            in_X2 = true;
            break;
        } else
        if (y > *(X2 + j) && y < *(X2 + j + 1)) break; //Если не в узле, фиксируем индекс предыдущего узла
    }

    if (in_X1 && in_X2) { //Если попали в два узла сетки, возвращаем уже известное значение
        return *((Y + i*n) + j);
    } else
    if (in_X1) { //Если в узле только по X1, возвращаем lin_int между узлами X2
        return lin_int(n, X2, (Y+i*n), y);
    } else
    if (in_X2) { //Если в узле только по X2, возвращаем lin_int между узлами X1
        x1 = *((Y+i*n)+j);
        x2 = *((Y+(i+1)*n)+j);
        if (*(X1+i+1) == *(X1+i)){
            return x1 + (x2-x1) * (x-*(X1+i)) / (*(X1+i)*2); //два совпадающих значения в узлах
        }
        return x1 + (x2-x1) * (x-*(X1+i)) / (*(X1+i+1) - *(X1+i));
    } else { //Если ни в какой узел не попали
        if (*(X1+i+1) == *(X1+i)){
            return x1 + (x2-x1) * (x-*(X1+i)) / (*(X1+i)*2); //два совпадающих значения в узлах
        }
        x1 = lin_int(n, X2, (Y+i*n), y); //Если не попали ни в какой узел, вычисляем x1, x2 и возвращаем lin_int между ними
        x2 = lin_int(n, X2, (Y+(i+1)*n), y);
        return x1 + (x2-x1) * (x-*(X1+i)) / (*(X1+i+1) - *(X1+i));
    }
}


void test_lin_int_mass(void){
    double X1[4] = { 0.3, 1.0, 4.0, 10.0 };
    double X2[3] = { 0.0, 90.0, 180.0 };
    double Y[4][3] =
        {/*                  0             90             180        */
        /*0.3*/            {1.0,         -0.107,         -0.5},
        /*1.0*/            {1.3,          -0.3,          -0.7},
        /*4.0*/            {1.5,          -0.2,          -0.6},
        /*10.*/            {1.53,        -0.253,         -0.5}
        };

    double i,j;
    for (i=0; i<=200; i+=15){
        printf("\t%.3lf", i);

    }
    printf("\n");
    for (i=0; i<=12; i+=1){
        printf("%.3lf", i);
        for(j=0; j<=200; j+=15){
            printf("\t%.3lf", lin_int_for_mass(4, 3, X1, X2, &Y[0][0], i, j));
        }
        printf("\n");
    }
}

int main()
{
    test_lin_int_mass();
    return 0;
}

В чем причина разных результатов?

Неправильный вывод (в VisualStudio):

    0.000   15.000  30.000  45.000  60.000  75.000  90.000  105.000 120.000 135.000 150.000 165.000 180.000 195.000
0.000   1.000   1.000   1.000   1.000   1.000   1.000   -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500
1.000   1.300   1.300   1.300   1.300   1.300   1.300   -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500
2.000   1.300   -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500
3.000   1.300   -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500
4.000   1.500   -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500
5.000   1.500   -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500
6.000   1.500   -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500
7.000   1.500   -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500
8.000   1.500   -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500
9.000   1.500   -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500
10.000  1.500   -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500
11.000  1.500   -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500
12.000  1.500   -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500  -0.500

Правый вывод (в кодовых блоках):

    0.000   15.000  30.000  45.000  60.000  75.000  90.000  105.000 120.000 135.000 150.000 165.000 180.000 195.000
0.000   1.000   0.816   0.631   0.447   0.262   0.077   -0.107  -0.172  -0.238  -0.304  -0.369  -0.434  -0.500  -0.500
1.000   1.300   1.033   0.767   0.500   0.233   -0.033  -0.300  -0.367  -0.433  -0.500  -0.567  -0.633  -0.700  -0.700
2.000   1.367   1.094   0.822   0.550   0.278   0.006   -0.267  -0.333  -0.400  -0.467  -0.533  -0.600  -0.667  -0.667
3.000   1.433   1.156   0.878   0.600   0.322   0.044   -0.233  -0.300  -0.367  -0.433  -0.500  -0.567  -0.633  -0.633
4.000   1.500   1.217   0.933   0.650   0.367   0.083   -0.200  -0.267  -0.333  -0.400  -0.467  -0.533  -0.600  -0.600
5.000   1.505   1.219   0.934   0.648   0.362   0.077   -0.209  -0.271  -0.334  -0.396  -0.458  -0.521  -0.583  -0.583
6.000   1.510   1.222   0.934   0.646   0.358   0.070   -0.218  -0.276  -0.334  -0.392  -0.450  -0.508  -0.567  -0.567
7.000   1.515   1.225   0.935   0.644   0.354   0.064   -0.227  -0.280  -0.334  -0.388  -0.442  -0.496  -0.550  -0.550
8.000   1.520   1.227   0.935   0.642   0.350   0.057   -0.235  -0.285  -0.335  -0.384  -0.434  -0.484  -0.533  -0.533
9.000   1.525   1.230   0.935   0.640   0.346   0.051   -0.244  -0.290  -0.335  -0.380  -0.426  -0.471  -0.517  -0.517
10.000  1.530   1.233   0.936   0.639   0.341   0.044   -0.253  -0.294  -0.335  -0.377  -0.418  -0.459  -0.500  -0.500
11.000  1.530   1.233   0.936   0.639   0.341   0.044   -0.253  -0.294  -0.335  -0.377  -0.418  -0.459  -0.500  -0.500
12.000  1.530   1.233   0.936   0.639   0.341   0.044   -0.253  -0.294  -0.335  -0.377  -0.418  -0.459  -0.500  -0.500

Каждый раз, когда я читаю «Здесь другое поведение, чем там…», я думаю о «Неопределенном поведении». Знаете ли вы об этом? В любом случае, пожалуйста, предоставьте минимально воспроизводимый пример, в идеале с жестко запрограммированным вводом, который демонстрирует то, что вы наблюдаете, желательно сопровождаемый заявлением о том, что вы действительно используете его одинаково в обеих средах. Приятно иметь: комментарии на английском языке.

Yunnosch 04.05.2024 11:33

В вашем коде слишком много однобуквенных переменных, сложно понять, что они обозначают.

Harith 04.05.2024 11:41

@Харит, я написал, какая переменная за что отвечает, надеюсь, ты это понимаешь. Я также добавил комментарии для представления структуры массивов.

Alex N 04.05.2024 11:46

какой вывод правильный, а какой неправильный? и чем они отличаются?

Ahmed AEK 04.05.2024 11:47

Добавил богболт для образца godbolt.org/z/7af9W4Mnr

Johann Gerell 04.05.2024 11:48

@JohannGerell только что добавил дезинфицирующее средство и обнаружил ошибку, godbolt.org/z/M38hsE4rM

Ahmed AEK 04.05.2024 11:51

Пожалуйста, включите предупреждения компилятора: 'lin_int': не все пути управления возвращают значение. Если других путей действительно нет, то не запутывайте код ненужными операторами else.

Weather Vane 04.05.2024 11:54

Будьте осторожны при сравнении значений с плавающей запятой на предмет равенства.

Weather Vane 04.05.2024 12:02

Добавлены правильные и неправильные выводы.

Alex N 04.05.2024 12:05
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
9
78
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Функция lin_int_for_mass() имеет неопределенное поведение как минимум в двух местах:

  1. Вы не инициализируете переменные x1 и x2 на каждом пути через эту функцию; в частности, если ни in_X1, ни in_X2 не являются истинными, вы можете нажать оператор возврата в строке 77, даже не инициализируя их.
  2. То же самое касается самих переменных in_X1 и in_X2; у вас есть UB, если только оба x == *(X1 + i) для любых x, X1 и i и y == *(X2 + j) для любых y, X2 и j.

Эта проблема может возникнуть и в других местах вашего кода; Как правило, избегайте объявления переменной без ее инициализации. Если вы не используете древний языковой стандарт, вам не нужно объявлять переменные поверх функции, а затем назначать их позже (что вы можете забыть сделать); вы можете объявить и инициализировать их прямо там, где они вам нужны.

Основная проблема была в функции lin_int_for_mass. Я не инициализировал in_X1 и in_X2 как false по умолчанию.

Другие вопросы по теме