LINUX.ORG.RU

Говорили что Перл старый, ни на что не способный язык. Проверим?

 , , , ,


9

4

Говорили что Перл старый, ни на что не способный язык. Проверим?

Задачка:

Необходимо для каждой пары слов получить новое слово, так, чтобы окончание первого совпадало с началом второго, например, шлакоблок + окунь = шлакоблокунь. Это слово надо вывести в стандартный поток вывода.Если слова возможно соединить несколькими способами, надо выбрать тот, что обеспечивает максимальную общую часть, например папа + папаха = папаха (а не папапаха). Необходимо написать последнее условие.

Я просто взял практически первое попавшаяся задание.

На Перле программа заняла 5 строк не считая ввода-вывода. С вводом-выводом - 7 строк.

А как у вас? На ваших Супер-пупер языках?

Перемещено xaizek из general

Перемещено hobbit из talks



Последнее исправление: Pinkbyte (всего исправлений: 1)

Ответ на: комментарий от kompospec

Ок, а как это относится к вопросу о низкой производительности Perl для целевой задачи?

demensdeum
()
Ответ на: комментарий от kompospec

Да, проблема есть с компилятором g++ в Linux и функцией getline(). В файле словаря каждая строка заканчивается на \r\n. Это и ведёт к некорректному поведению. Если в geany выполнить в Документ->Установить Окончания строк->LF(Unix), то всё заработает.

Kogrom
()
Ответ на: комментарий от Kogrom

Странно у меня g++ и clang++ работают нормально, g++ медленее только на 10 сек. Не выводит у kompspec по той причине что, как мне известно, CPU у него старенький и не успевает сделать весь перебор.

demensdeum
()
Ответ на: комментарий от demensdeum

Можно немного подчистить и всё будет работать с исходным файлом словаря:

#include <iostream>
#include <fstream>
#include <ctime>
#include <string>
#include <vector>
using namespace std;

void check_combine(string &res, size_t &len, const string &s1, const string &s2)
{
    len = 0;
    for(auto &ch: s1)
    {
        if(len == s2.size())
        {
            break;
        }
        if(ch == s2.at(len))
        {
            len += 1;
        }
        else
        {
            len = 0;
        }
    }
    if(!len)
    {
        res = "";
    }
    else
    {
        string s3  {s2};
        s3.erase(0, len);
        res = s1;
        res += s3;
    }
}

void getlines(vector<string> &lines, fstream & f)
{
    string str;
    while(getline(f, str))
    {
        if(str.back() == '\n')
            str.pop_back();
        if(str.back() == '\r')
            str.pop_back();
        lines.push_back(str);
    }
}

int main()
{
    fstream inFile;
    inFile.open ("/home/serg/cpp/russian_nouns.txt", std::fstream::in);
    vector<string> lines;
    getlines(lines, inFile);
    size_t maxLen  {0};
    size_t rusMaxLen  {0};
    string maxRes  {""};
    time_t startTime = time(nullptr);
    size_t counter  {0};
    for(auto &s1: lines)
    {
        for(auto &s2: lines)
        {
            counter += 1;
            if(s1 == s2)
            {
                continue;
            }
            if(s1.size() < maxLen)
            {
                continue;
            }
            if(s2.size() < maxLen)
            {
                continue;
            }
            size_t len  {0};
            string res;
            check_combine(res, len, s1, s2);
            if(res == s1)
            {
                continue;
            }
            if(res == s2)
            {
                continue;
            }
            if(len > maxLen)
            {
                maxLen = len;
                rusMaxLen = maxLen / 2;
                time_t delta = time(nullptr) - startTime;
                string deltaStr  {s2};
                deltaStr.erase(len);
                maxRes = deltaStr + " - " + s1 + '-' + s2;
                cout << counter << "\t прошло: " << delta << " секунд, длина: ";
                cout << rusMaxLen << ", " << maxRes << '\n';
            }
        }
    }
    cout << "\n\nРезультат: " << rusMaxLen << ", " << maxRes << '\n';
    time_t delta = time(nullptr) - startTime;
    cout << "Полное время переборов: " << delta;
    inFile.close();
    return 0;
}

Kogrom
()
Ответ на: комментарий от Kogrom
"/home/serg/cpp/russian_nouns.txt"

бывает, поправил

#include <iostream>
#include <fstream>
#include <ctime>
#include <string>
#include <vector>
using namespace std;

void check_combine(string &res, size_t &len, const string &s1, const string &s2)
{
    len = 0;
    for(auto &ch: s1)
    {
        if(len == s2.size())
        {
            break;
        }
        if(ch == s2.at(len))
        {
            len += 1;
        }
        else
        {
            len = 0;
        }
    }
    if(!len)
    {
        res = "";
    }
    else
    {
        string s3  {s2};
        s3.erase(0, len);
        res = s1;
        res += s3;
    }
}

void getlines(vector<string> &lines, fstream & f)
{
    string str;
    while(getline(f, str))
    {
        if(str.back() == '\n')
            str.pop_back();
        if(str.back() == '\r')
            str.pop_back();
        lines.push_back(str);
    }
}

int main()
{
    fstream inFile;
    inFile.open ("russian_nouns.txt", std::fstream::in);
    vector<string> lines;
    getlines(lines, inFile);
    size_t maxLen  {0};
    size_t rusMaxLen  {0};
    string maxRes  {""};
    time_t startTime = time(nullptr);
    size_t counter  {0};
    for(auto &s1: lines)
    {
        for(auto &s2: lines)
        {
            counter += 1;
            if(s1 == s2)
            {
                continue;
            }
            if(s1.size() < maxLen)
            {
                continue;
            }
            if(s2.size() < maxLen)
            {
                continue;
            }
            size_t len  {0};
            string res;
            check_combine(res, len, s1, s2);
            if(res == s1)
            {
                continue;
            }
            if(res == s2)
            {
                continue;
            }
            if(len > maxLen)
            {
                maxLen = len;
                rusMaxLen = maxLen / 2;
                time_t delta = time(nullptr) - startTime;
                string deltaStr  {s2};
                deltaStr.erase(len);
                maxRes = deltaStr + " - " + s1 + '-' + s2;
                cout << counter << "\t прошло: " << delta << " секунд, длина: ";
                cout << rusMaxLen << ", " << maxRes << '\n';
            }
        }
    }
    cout << "\n\nРезультат: " << rusMaxLen << ", " << maxRes << '\n';
    time_t delta = time(nullptr) - startTime;
    cout << "Полное время переборов: " << delta;
    inFile.close();
    return 0;
}
Запускаем
clang++ test.cpp -Ofast -o Ofast && ./Ofast
417      прошло: 0 секунд, длина: 4, ажур - абажур-ажурность
878657   прошло: 0 секунд, длина: 5, генез - абиогенез-генезис
4009466  прошло: 0 секунд, длина: 6, датель - авансодатель-дательница
4061251  прошло: 0 секунд, длина: 9, держатель - авансодержатель-держательница
4093816  прошло: 0 секунд, длина: 11, содержатель - авансодержатель-содержательность
265157673        прошло: 1 секунд, длина: 13, производитель - воспроизводитель-производительность
Результат: 13, производитель - воспроизводитель-производительность
Полное время переборов: 10

demensdeum
()
Ответ на: комментарий от Siborgium

Да, круто. Как я понимаю, основной выигрыш за счёт использования методов string_view. Можно ещё ускорить, если newlines отсортировать по убыванию длины строк, а затем циклы прерывать по достижению строки, которая меньше найденного максимального пересечения. Но я не стал заморачиваться, да и вроде уговор был не менять порядок.

Обычно русские буквы занимают 2 байта, отсюда деление на 2

Только символ № занимает 3 байта, так что нормально.

Kogrom
()
Ответ на: комментарий от Silerus

Похоже clang++ унижен и уничтожен с помощью g++ и pgo, далее старый вариант кода

#include <iostream>
#include <fstream>
#include <ctime>
#include <string>
#include <vector>
using namespace std;

void check_combine(string &res, size_t &len, const string &s1, const string &s2)
{
    len = 0;
    for(auto &ch: s1)
    {
        if(len == s2.size())
        {
            break;
        }
        if(ch == s2.at(len))
        {
            len += 1;
        }
        else
        {
            len = 0;
        }
    }
    if(!len)
    {
        res = "";
    }
    else
    {
        string s3  {s2};
        s3.erase(0, len);
        res = s1;
        res += s3;
    }
}

void getlines(vector<string> &lines, fstream & f)
{
    string str;
    while(getline(f, str))
    {
        lines.push_back(str);
    }
}

int main()
{
    fstream inFile;
    inFile.open ("russian_nouns.txt", std::fstream::in);
    vector<string> lines;
    getlines(lines, inFile);
    inFile.close();
    auto i = 0;
    size_t maxLen  {0};
    size_t rusMaxLen  {0};
    string maxRes  {""};
    time_t startTime = time(nullptr);
    size_t counter  {0};
    for(auto &s1: lines)
    {
        for(auto &s2: lines)
        {
            counter += 1;
            if(s1 == s2)
            {
                continue;
            }
            if(s1.size() < maxLen)
            {
                continue;
            }
            if(s2.size() < maxLen)
            {
                continue;
            }
            size_t len  {0};
            string res;
            // if (i % 1000000 == 0) {
            //   time_t delta = time(nullptr) - startTime;
            //   cout << "s1 " << s1 << endl << "s2 "<< s2 << "\t прошло: " << delta << " секунд" << endl;
            // }
            // i++;
            check_combine(res, len, s1, s2);
            if(res == s1)
            {
                continue;
            }
            if(res == s2)
            {
                continue;
            }
            if(len > maxLen)
            {
                maxLen = len;
                rusMaxLen = maxLen / 2;
                time_t delta = time(nullptr) - startTime;
                string deltaStr  {s2};
                deltaStr.erase(len);
                maxRes = deltaStr + " - " + s1 + '-' + s2;
                cout << counter << "\t прошло: " << delta << " секунд, длина: ";
                cout << rusMaxLen << ", " << maxRes << '\n';
            }
        }
    }
    cout << "\n\nРезультат: " << rusMaxLen << ", " << maxRes << '\n';
    time_t delta = time(nullptr) - startTime;
    cout << "Полное время переборов: " << delta;
    return 0;
}

echo "---"
g++ test.cpp -Ofast -fprofile-generate="profile" -o pgo
echo "---"
./pgo
echo "---"
g++ test.cpp -Ofast -fprofile-use="profile" -o pgo
echo "---"
./pgo
echo "---"
clang++ test.cpp -Ofast -o OfastClang
echo "---"
./OfastClang
Запускаем
PGO G++ - полное время переборов: 67
Clang++ - полное время переборов: 84

demensdeum
()
Последнее исправление: demensdeum (всего исправлений: 2)
Ответ на: комментарий от demensdeum

Всем:

Я дописал подпрограмму для расчёта без регулярок - Время одинаковое что и с правильной регуляркой.

#!/usr/bin/perl

use utf8;
use open qw(:std :utf8); 

$t = time();

$| = 1;
open D, 'russian_nouns.txt';

for(0..3000) {
  $vv=<D>;
  $vv =~ s/\s+$//;
  @d = (@d, $vv);
  }

close D;
@d2 = @d;


for $v (@d){
    ++$ii; if (++$j>99){
    $t2 = time()-$t;
    print $ii." прошло $t2 секунд. $sov1 $str\n"; $j=0;}

  for $v2 (@d2) {&resh3 ()}
  
M1:  
  }
  
sub resh3 {
  
  $lv = length $v;
  $lv2 = length $v2;

  if($lv>$lv2) {
  
    for($i=$lv2; $i>1; $i--) {
      $c = substr ($v, -$i,);
      $c2 = substr ($v2, 0, $i);
      if (($c eq $c2) and ($c ne $v2) and ($c ne $v)){
          $sov = length $c;
          if ($sov>$sov1){$sov1=$sov; $str="$c = $v-$v2"}
          }
        
  
      }

  
  }
  else {
    
        for($i=$lv; $i>1; $i--) {
      $c = substr ($v2, -$i,);
      $c2 = substr ($v, 0, $i);
      if (($c eq $c2) and ($c ne $v2) and ($c ne $v)){
          $sov = length $c;
          if ($sov>$sov1){$sov1=$sov; $str="$c = $v-$v2"}
          }
        
  
      }
    
    
    
    }
  
  
}
  

sub resh1 {  
    $r=''; $l='';
    for(split(//,$v2)){
      $r .= $_;
      if ($v =~ /$r$/) {$l=$r}  
      }
    #print "$v-$l-$v2\n" if length $l>4 and $v ne $l;
    
    if ($l and ($l ne $v2) and ($l ne $v)){
    $sov = length $l;
    if ($sov>$sov1){$sov1=$sov; $str="$l - $v-$v2"}
}
}


sub resh2 {
  
    if($v ne $v2) {
    $_ = "$v $v2";
    /([^ ]*?)([^ ]*) \2/;
    
    if ($2 and ($2 ne $v2) and ($2 ne $v)){
    $sov = length $2;
    if ($sov>$sov1){$sov1=$sov; $str="$2 - $_"}

}
  }
  
  
  }


kompospec
() автор топика
Ответ на: комментарий от kompospec

Если я не ошибся в программе можно сделать выводы про Регулярки:

  1. Плохая регулярка может сильно замедлить программу;
  2. Хорошая регулярка - не замедлит программу, но и не ускорит;
  3. Если не умеешь писать регулярки - не пиши, где это критично по скорости;
  4. Простые регулярки испортить очень трудно, но возможно.
kompospec
() автор топика
Ответ на: комментарий от kompospec

Я рад что вы пришли к выводу что лучше переписать на С++

demensdeum
()
Ответ на: комментарий от demensdeum

Да. Конечно. Много раз. Пишешь одну строку вместо 100 на Плюсах Она работает минуту. Ну и что? А 100 строк на Плюсах писать дольше гораздо.

kompospec
() автор топика
Ответ на: комментарий от kompospec

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

Никтож мою прогу на Перл не хочет запускать.

Ее запустили дважды и получили цифры, не в пользу Перла, на типичной для Перла задаче.

Насчет доминирования скажу, что по итогу всех замеров получилось что Перл позволяет доминировать в области быстрого написания медленных программ.
Мне нужны были цифры, я их получил, можете дальше продолжать доминировать уже на С++.

demensdeum
()
Последнее исправление: demensdeum (всего исправлений: 1)
Ответ на: комментарий от demensdeum

Обработка огромных файлов - это ни есть типичная задача для Перл. Тем более для Вебпрограммиста к которым я себя отношу.

kompospec
() автор топика
Ответ на: комментарий от mister_VA

прогу интегрирования методом Симпсона
которые я делал в школе

Или это школа была не совсем обычная или вы нас обманываете.

anc ★★★★★
()
Ответ на: комментарий от kompospec

Обработка огромных файлов - это ни есть типичная задача для Перл.

Ниразу.

anc ★★★★★
()
Ответ на: комментарий от kompospec

А программу на С++ я не смог запустить ниразу.

конпелировать не пробовали?

anc ★★★★★
()
Ответ на: комментарий от mersinvald

Да-да. Я уже 2 день прошу конвертировать мою программу на С++ чтоб проверить скорость. А С++ники никак не могут написать 3 строчки:

#!/usr/bin/perl

use utf8;
use open qw(:std :utf8); 

$t = time();

$| = 1;
open D, 'russian_nouns.txt';

for(0..3000) {
  $vv=<D>;
  $vv =~ s/\s+$//;
  @d = (@d, $vv);
  }

close D;
@d2 = @d;


for $v (@d){
    ++$ii; if (++$j>99){
    $t2 = time()-$t;
    print $ii." прошло $t2 секунд. $sov1 $str\n"; $j=0;}

  for $v2 (@d2) {&resh3 ()}
  
M1:  
  }
  
sub resh3 {
  
  $lv = length $v;
  $lv2 = length $v2;

  if($lv>$lv2) {
  
    for($i=$lv2; $i>1; $i--) {
      $c = substr ($v, -$i,);
      $c2 = substr ($v2, 0, $i);
      if (($c eq $c2) and ($c ne $v2) and ($c ne $v)){
          $sov = length $c;
          if ($sov>$sov1){$sov1=$sov; $str="$c = $v-$v2"}
          }
        
  
      }

  
  }
  else {
    
        for($i=$lv; $i>1; $i--) {
      $c = substr ($v2, -$i,);
      $c2 = substr ($v, 0, $i);
      if (($c eq $c2) and ($c ne $v2) and ($c ne $v)){
          $sov = length $c;
          if ($sov>$sov1){$sov1=$sov; $str="$c = $v-$v2"}
          }
        
  
      }
    
    
    
    }
  
  
}
  

sub resh1 {  
    $r=''; $l='';
    for(split(//,$v2)){
      $r .= $_;
      if ($v =~ /$r$/) {$l=$r}  
      }
    #print "$v-$l-$v2\n" if length $l>4 and $v ne $l;
    
    if ($l and ($l ne $v2) and ($l ne $v)){
    $sov = length $l;
    if ($sov>$sov1){$sov1=$sov; $str="$l - $v-$v2"}
}
}


sub resh2 {
  
    if($v ne $v2) {
    $_ = "$v $v2";
    /([^ ]*?)([^ ]*) \2/;
    
    if ($2 and ($2 ne $v2) and ($2 ne $v)){
    $sov = length $2;
    if ($sov>$sov1){$sov1=$sov; $str="$2 - $_"}

}
  }
  
  
  }

sub resh {

  $str = $_;
  
  }

kompospec
() автор топика
Ответ на: комментарий от Kogrom

Программа не запускается на полном файле. Но ведь можно сделать из полного файла - часть. Почему мне никто вчера про это не подсказал?

kompospec
() автор топика
Ответ на: комментарий от kompospec

Есть! В исходном файле или в вашей проге, вероятно, что что-то с кодировкой нитак. Перезаписал этот файл и ваша программа заработала!

417	 прошло: 0 секунд, длина: 4, ажур - абажур-ажурность
878674	 прошло: 0 секунд, длина: 5, генез - абиогенез-генезис
4009544	 прошло: 2 секунд, длина: 6, датель - авансодатель-дательница
4061330	 прошло: 2 секунд, длина: 9, держатель - авансодержатель-держательница
4093895	 прошло: 2 секунд, длина: 11, содержатель - авансодержатель-содержательность
265162841	 прошло: 29 секунд, длина: 13, производитель - воспроизводитель-производительность


Результат: 13, производитель - воспроизводитель-производительность
Полное время переборов: 161

------------------
(program exited with code: 0)
Press return to continue




kompospec
() автор топика
Ответ на: комментарий от kompospec

раз это прога работает на моём компе - значит нужно написать аналогичную на Перл. И тогда, наконец то, мы сможем сравнить скорости.

kompospec
() автор топика
Ответ на: комментарий от kompospec

Ого!

$ ./a.out
417	 прошло: 0 секунд, длина: 4, ажур - абажур-ажурность
878674	 прошло: 0 секунд, длина: 5, генез - абиогенез-генезис
4009544	 прошло: 1 секунд, длина: 6, датель - авансодатель-дательница
4061330	 прошло: 1 секунд, длина: 9, держатель - авансодержатель-держательница
4093895	 прошло: 1 секунд, длина: 11, содержатель - авансодержатель-содержательность
265162841	 прошло: 3 секунд, длина: 13, производитель - воспроизводитель-производительность


Результат: 13, производитель - воспроизводитель-производительность

kompospec
() автор топика
Ответ на: комментарий от kompospec

А как Питон? Как он себя чувствует с этой задачей? Есть ли ещё ЯП которые смогут справиться с этой задачей?

kompospec
() автор топика
Ответ на: комментарий от kompospec

Потому что на С++ программируют только старенькие дедушки.

kompospec
() автор топика
Ответ на: комментарий от kompospec

Поздравляю! Вернусь к теме о суммарном времени написания и выполнения кода. Изначальный код на моём самодельном языке был такой:

import time

def check_combine
    mref res:string len:int
    cref s1:string s2:string
    *len2 @int @size s2
    len = 0
    for *ch in s1
        if len len2
            break
        if ch s2|len
            len + 1
        else
            len = 0
    ifnot len
        res = ""
    else
        *s3 @string s2 @erase 0 len
        res = s1 + s3
    
def main
    *inFile @file @set_mode "r" @open "russian_nouns.txt"
    *lines @array|string 
    lines inFile @getlines
    *maxLen @int 0
    *rusMaxLen @int 0
    *maxRes @string ""
    *startTime @int @time:time
    *counter @int 0
    for *s1 in lines
        for *s2 in lines
            counter + 1
            if s1 s2
                continue
            *len1 @int @size s1
            *len2 @int @size s2
            if < len1 maxLen
                continue
            if < len2 maxLen
                continue
            *len @int 0
            *res @string
            res len @check_combine s1 s2
            if res s1
                continue
            if res s2
                continue
            if > len maxLen
                maxLen = len
                rusMaxLen = maxLen / 2
                *delta @int @time:time - startTime
                *deltaStr @string s2 @erase len
                maxRes = deltaStr + " - " s1 "-" s2
                @print* counter "\t прошло: " delta " секунд, длина: " rusMaxLen ", " maxRes "\n"
    @print* "\n\nРезультат: " rusMaxLen ", " maxRes "\n" 
    *delta @int @time:time - startTime
    @print* "Полное время переборов: " delta
    inFile @close

По длине он 1673 символа против 2457 на C++. То есть примерно в 1,5 раза короче. При том, можно ещё сократить, если сделать простейший вывод типов в конструкторе, а также открыть доступ к длине строки через переменную (это будет плохо с точки зрения инкапсуляции, но для маленьких одноразовых программ такое оправдано).

Но это не потому что C++ плохой. Для больших многоразовых программ он лучше. Если команда работает - он лучше, хотя хуже, чем Java и C#. Для маленьких одноразовых программ лучше были Перл и Питон, если нет требований по времени. Но Перл теперь заменяют на Раку, а Питон переусложнили.

Kogrom
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.