Сравнение двух значений (используется для тестирования)

Главная Форумы Программирование Язык Пифагор Примеры Сравнение двух значений (используется для тестирования)

Помечено: 

В этой теме 1 ответ, 1 участник, последнее обновление  Васильев Владимир Сергеевич 1 неделя, 6 дн. назад.

  • Автор
    Сообщения
  • #4170

    Функция equals выполняет сравнение двух значений являющихся либо элементами встроенных типов, либо списками данных. При этом, для сравнения списков используется функция vec_equals, на вход которой могут подаваться списки данных произвольной структуры:

    equals << funcdef X {
      A << X:1;
      B << X:2;
      
      TypeA << A:type;
      TypeB << B:type;
      [((TypeA, TypeB):[!=, =]):?]^(
        false,
        {
          block {
            [((TypeA, datalist):[!=, =]):?]^(
              {X:=},
              {X:vec_equals}
            ) >> break
          }
        }
      ):.:. >> return;
    }

    Для обоих аргументов определяется тип с помощью встроенной операции type, если типы не совпадают — возвращается false. В противном случае, если типы не совпадают с datalist (список данных) — выполняется встроенная операция сравнения, а при совпадении — функция vec_equals.

    vec_equals << funcdef X {
      VectorA << X:1;
      VectorB << X:2;
    
      SizeA << VectorA:|;
      SizeB << VectorB:|;
      [((SizeA, SizeB):[!=,=]):?]^(
        false, 
        {
          block {
            Pairs << X:#:[];
            CountEquals << ((Pairs:equals):?):|; 
            [((CountEquals, SizeA):[!=,=]):?]^(
              false, true
            ) >> break
          }
        }
      ):. >> return;
    }

    В функции vec_equals для каждого из исходных списков определяется длина — если полученные значения не совпали, функция возвращает false, иначе — список-аргумент функции транспонируется и полученный список преобразуется в параллельный. В результате список типа
    ((x1,x2,...xn), (y1, y2, … yn))
    преобразуется сначала в список пар:
    ((x1, y1), (x2, y2), … (xn, yn)),
    а затем — в параллельный список пар (Pairs):
    [(x1, y1), (x2, y2), … (xn, yn)].
    Над параллельным списком пар элементов выполняется функция equals, в результате сформируется параллельный список значений логического типа, который помещается внутрь списка данных (при этом раскрывается в соответствии с правилами эквивалентных преобразований). Применение к полученному списку оператора селекции (?) приведет к формированию списка индексов true-значений, т. е. номеров пар, значения в которых совпали. Для полученного списка определяется длина (CountEquals), при совпадении которой с длиной одного из исходных списков возвращается true, иначе — false.

    Функция тестировалась следующим образом:

    test.equals << funcdef {
      Cases << [
        ("numbers_equal", ((1,1):equals, true)),
        ("numbers_not_equal", ((5,4):equals, false)),
        ("flatten_list_not_equal", (((1,2,3),(4,5,6)):equals, false)),
        ("flatten_list_equal", (((1,2,3),(1,2,3)):equals, true)),
        ("list_structure_not_equal", ((((1,2),3),(1,(2,3))):equals, false)),
        ("strings equals", (("hello","hello"):equals, true)),
        ("strings not equals", (("hello","world"):equals, false))
      ];
    
      return << (Cases:2:=);
    }

  • #4175

    Рассмотренный выше вариант хорошо подходит для сравнения целых чисел, однако, для сравнения дробных чисел необходимо использовать функцию нечеткого сравнения вместо оператора “=”. Код изменится следующим образом:

    equals << funcdef X {
      A << X:1;
      B << X:2;
      
      EqOp << [((X:|,3):[<,=]):?]^(=, X:3);
    
      TypeA << A:type;
      TypeB << B:type;
      [((TypeA, TypeB):[!=, =]):?]^(
        false,
        {
          block {
            [((TypeA, datalist):[!=, =]):?]^(
              {(X:1, X:2):EqOp},
              {X:vec_equals}
            ) >> break
          }
        }
      ):.:. >> return;
    
    }
    
    vec_equals << funcdef X {
      VectorA << X:1;
      VectorB << X:2;
    
      SizeA << VectorA:|;
      SizeB << VectorB:|;
      [((SizeA, SizeB):[!=,=]):?]^(
        false, 
        {
          block {
            EqOp << [((X:|,3):[<,=]):?]^(=, X:3);
            Ops << (EqOp, SizeA):dup;
            
            Pairs << (VectorA, VectorB, Ops):#:[];
            CountEquals << ((Pairs:equals):?):|; 
            [((CountEquals, SizeA):[!=,=]):?]^(
              false, true
            ) >> break
          }
        }
      ):. >> return;
    }
    
    test.equals << funcdef {
      Cases << [
        ("numbers_equal", ((1,1):equals, true)),
        ("numbers_not_equal", ((5,4):equals, false)),
        ("flatten_list_not_equal", (((1,2,3),(4,5,6)):equals, false)),
        ("flatten_list_equal", (((1,2,3),(1,2,3)):equals, true)),
        ("list_structure_not_equal", ((((1,2),3),(1,(2,3)),=):equals, false)),
        ("strings equals", (("hello","hello"):equals, true)),
        ("strings not equals", (("hello","world"):equals, false)),
        ("equals with fuzzy compare", ((1,1.00000001,fuzzy_compare):equals, true)),
        ("not equals with fuzzy compare", ((1,1.001,fuzzy_compare):equals, false)),
        ("equals with fuzzy compare and list structure", (((1.000001,(2)),(1,(2.000001)), fuzzy_compare):equals, true)),
        ("not equals with fuzzy compare and list structure", ((((1.0001,2),3),((1,2),3),fuzzy_compare):equals, false))
      ];
    
      return << Cases:2:=;
    }

    В обоих функциях добавился фрагмент, отвечающий за выбор оператора (EqOp). Если аргументов
    меньше трех – то по умолчанию берется оператор “=”, иначе берется функция, переданная третьим аргументом. EqOp используется при сравнении двух элементов если они не являются списками данных ({(X:1, X:2):EqOp}). Если же на вход поданы два списка – то сравнению подлежат все их элементы – поэтому оператор сравнения надо скопировать столько раз, сколько есть элементов в списках: Ops << (EqOp, SizeA):dup;.

Для ответа в этой теме необходимо авторизоваться.