LINUX.ORG.RU

Fortran 2018: новый стандарт языка

 , ,


4

5

2-го декабря 2018-го года Международная Организация по Стандартизации (ISO) опубликовала ISO/IEC 1539:2018, ранее известный под названием Fortran 2015.

Новый стандарт расширяет возможности взаимодействия с программами на C и параллельного программирования:

  • Введён новый тип CFI_cdesc_t, содержащий информацию о типе элементов, ранге, размере передаваемого массива и способе выделения его памяти. Ранее на сторону программы, написанной на языке C, вместо массивов чисел можно было передать только «голые» указатели, и о соблюдении границ массивов приходилось заботиться вручную.
  • Введено понятие команды (team), позволяющее разделить выполняющуюся на кластере программу на несколько сравнительно независимых подмножеств процессов.
  • Появилась возможность обработки ошибок отдельных процессов кластера (fail image и аргумент stat= вызовов change team, end team, event post, form team, sync all, sync images, sync team).
  • Добавлены атомарные операции над переменными (atomic_add, atomic_and, atomic_or, atomic_xor, atomic_fetch_add, atomic_fetch_and, atomic_fetch_or, atomic_fetch_xor, atomic_cas).
  • Улучшена совместимость со стандартом ISO/IEC/IEEE 60559:2011 для чисел с плавающей запятой.

Следующая версия стандарта временно называется Fortran 202x.

Новые возможности Fortran 2018

Бесплатно доступный черновик стандарта

>>> Подробности

★★★★★

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

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

Я на питоне только препроцессинг/постпроцессинг делаю (начальные/граничные условия, графики и т.п.). Для тяжёлых задач использую f2py (пора с этим завязывать). Для распараллеливания переписываю всё на голом фортране+mpi.

yvv ★★☆
()
Ответ на: комментарий от eao197

Заголовок события: (1X,F9.4, 3(1X,I15))
Тело (350-2000 строк): (1x,7(1XF9.4),1XI3,1XE12.4)

У меня вопрос к вменяемым фортранщикам в этой теме. Правильно ли я понимаю, что описанный таким образом заголовок — это, по сути:
<space><float><space><int><space><int><space><int>
и не более того? Без всяких круглых скобок и запятых во входном потоке?

Это эквивалентно " %9.4f %15d %15d %15d" и " %9.4f %9.4f %9.4f %9.4f %9.4f %9.4f %9.4f %3d %12.4e", но 1X при чтении пропускает ровно один любой символ, не обязательно пробел. По умолчанию, после считывания подобной записи фортран пропускает всё до конца строки; при записи вставляется перенос строки.

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

Спасибо!

Тогда, если не заморачиваться на пропуск одного любого символа при чтении, то заголовок может на C++ считываться таким образом:

struct header_type {
  double a_;
  int b_;
  int c_;
  int d_;
  int e_;
};
std::istream & operator>>(std::istream & from, header_type & h) {
  return (from >> h.a_ >> h.b_ >> h.c_ >> h.d_ >> h.e_);
}

header_type load_header(std::istream & from) {
  header_type result;
  from >> result;
  return result;
}

Аналогично будет и для содержимого.

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

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

Хотелось бы узнать как сделать I/O на C быстрым. Есть какие-нибудь рецепты?

Использовать устройства В/В и соотв. аппаратные интерфейсы с достаточной попускной способностью и/или временем отклика. Использовать соотв. ОС и драйвера.

В/В по определению подразумевает наличие аппаратных устройств из которых или в которые осуществляется чтение/запись. Чтение из памяти В/В не является, как и все, что происходит после возврата из системного вызова ОС.

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

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

Там есть ещё ряд подводных камней, и написать совместимый парсер довольно непросто. Но в первом приближении пойдёт.

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

Обычно это пишется в заголовке. Считай, что это один из интов.

Вот программа, генерирующая файл на 1.5 Гб со случайными данными:

implicit none

type THeader
  real f
  integer length
  integer i(2)
endtype THeader

type TBody
  real f(7)
  integer i
  double precision e
endtype TBody

integer       f, i, j, k
type(THeader) h
type(TBody)   b

open(newunit=f, file='data', status='replace')

do i = 1, 15000
  print *, i
  h%f = rnd()
  h%length = 350 + irnd(2000 - 350)
  h%i(1) = irnd(1000000)
  h%i(2) = irnd(1000000)

  write (f, '(1X,F9.4,3(1X,I15))') h

  do j = 1, h%length
    do k = 1, 7
      b%f(k) = rnd()
    enddo
    b%i    = irnd(1000)
    b%e    = rnd()

    write (f, '(1X,7(1X,F9.4),1XI3,1XE12.4)') b
  enddo
enddo

close(f)

contains

function rnd()
  real rnd
  call random_number(rnd)
endfunction rnd

function irnd(imax)
  integer irnd
  integer imax
  
  real x
  call random_number(x)
  irnd = x * imax
endfunction irnd

end

Вот программа для чтения. Может, skvitek сможет выкатить что-то получше, но те физики, которых я знаю, написали бы примерно также (только без проверки на ошибки :E )

use iso_fortran_env

implicit none

type THeader
  real f
  integer length
  integer i(2)
endtype THeader

type TBody
  real f(7)
  integer i
  double precision e
endtype TBody

integer f, stat, i
type(THeader) h
type(TBody)   b

open(newunit=f, file='data', status='old')

do while (.true.)
  read (f, '(1X,F9.4,3(1X,I15))', iostat=stat) h
  if (stat /= 0) then
    if (stat == iostat_end) exit
    write (error_unit, *) 'Error while reading header: ', stat
    stop
  endif

  do i = 1, h%length
    read (f, '(1X,7(1X,F9.4),1XI3,1XE12.4)', iostat=stat) b
    if (stat /= 0) then
      if (stat == iostat_eor .or. stat == iostat_end) then
        write (error_unit, *) 'Unexpected end of file'
      else
        write (error_unit, *) 'Error while reading body: ', stat
      endif
      stop
    endif
  enddo
enddo

close(f)

end

Компилировать gfortran, так же, как обычным gcc (расширение файла с программой на фортране --- .f08). Если интересно, посравнивай. Если C++ будет тормозить, то я бы использовал mmap; с ним и перестановка блоков должна быть несложной, так как размер каждой записи известен.

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

Компилировать gfortran

Он же дикий тормоз.

Гиперболизируешь.

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

Примитивный вариант на C++14. Серьезно не проверялся.

Кроме того, там чтение идет в динамический контейнер. Для того, чтобы показать особо одаренным научным сотрудникам, как это тяжело в C++ поднять данные в память чтобы затем с этими данными что-то сделать.

Фортрана у меня нет, желания ставить его ради этого теста так же нет. Если кому не лень, то пусть прогонит бенчмарки сам.

#include <array>
#include <iostream>
#include <fstream>
#include <vector>
#include <stdexcept>

struct header_type {
	double a_;
	std::size_t len_;
	int b_;
	int c_;
};

std::istream & operator>>(std::istream & from, header_type & h) {
	return (from >> h.a_ >> h.len_ >> h.b_ >> h.c_);
}

struct data_item_type {
	std::array<double, 7> a_;
	int b_;
	double c_;
};

std::istream & operator>>(std::istream & from, data_item_type & d) {
	for(auto & i : d.a_)
		from >> i;
	return (from >> d.b_ >> d.c_);
}

struct data_block_type {
	header_type header_;
	std::vector<data_item_type> items_;
};

std::istream & operator>>(std::istream & from, data_block_type & d) {
	from >> d.header_;
	if(from) {
		d.items_.resize(d.header_.len_);
		for(auto & i : d.items_) {
			from >> i;
			if(!from)
				throw std::runtime_error("unexpected read error");
		}
	}
	return from;
}

std::vector<data_block_type> load_data(std::istream & from) {
	std::vector<data_block_type> result;
	while(from) {
		data_block_type d;
		from >> d;
		if(from)
			result.push_back(std::move(d));
	}
	return result;
}

int main(int argc, char ** argv) {
	if(2 == argc) {
		std::ifstream f(argv[1]);
		const auto data = load_data(f);
		std::cout << "items read: " << data.size() << std::endl;
	}
	else
		std::cout << "specify one file name as argument" << std::endl;
}

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

Всё же, речь шла только о чтении. Во-первых, обработка данных может быть и потоковой, во-вторых, в фортране есть свои особенности при работе с динамическими массивами (не помню, есть ли там нормальный realloc). Вот мои тесты, компилировались с -O2 -pipe -march=native -fno-stack-protector

Фортран --- приведён выше, только в конец добавлены две строки для проверки правильности работы:

print '(1X,F9.4,3(1X,I15))', h
print '(1X,7(1X,F9.4),1XI3,1XE12.4)', b

[fortran] > time ./fortran
    0.0900            1947          726626          566975
     0.6488    0.3638    0.3441    0.5092    0.9633    0.0133    0.6517  24   0.5360E+00

real    0m45.158s
user    0m44.944s
sys     0m0.212s

Решение eao197 на стандартных потоках C++:

#include <fstream>
#include <iostream>

struct header {
  float f;
  int   length;
  int   i[2];
};

struct body {
  float  f[7];
  int    i;
  double e;
};

int main() {
  std::ifstream f("data");

  struct header h;
  struct body b;

  while (f) {

    f >> h.f >> h.length >> h.i[0] >> h.i[1];

    for (int i = 0; i < h.length; ++i) {
      for (int j = 0; j < 7; ++j) f >> b.f[j];
      f >> b.i >> b.e;
    };
  };

  std::cout << h.f << ' ' << h.length << ' ' << h.i[0] << ' ' << h.i[1] << '\n';
  for (int i = 0; i < 7; ++i)
    std::cout << ' ' << b.f[i];
  std::cout << ' ' << b.i << ' ' << b.e << '\n';

  return 0;
};
[fortran] > time ./iostream
0.09 1947 726626 566975
 0.6488 0.3638 0.3441 0.5092 0.9633 0.0133 0.6517 24 0.536

real    0m43.548s
user    0m43.323s
sys     0m0.224s

Мой вариант с mmap

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>

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

struct header {
  float f;
  int   length;
  int   i[2];
};

struct body {
  float  f[7];
  int    i;
  double e;
};


void print_header(struct header* h) {
  printf(" %9.4f %15d %15d %15d\n", h->f, h->length, h->i[0], h->i[1]);
};

void print_body(struct body* b) {
  putchar(' ');
  for (int i = 0; i < 7; ++i) printf(" %9.4f", b->f[i]);
  printf(" %3d %12.4e\n", b->i, b->e);
};

int main() {
  int f = open("data", O_RDONLY);
  if (f < 0) {
    fprintf(stderr, "Failed to open `data': %s\n", strerror(errno));
    return 1;
  };

  struct stat stat;
  if (fstat(f, &stat) < 0) {
    fprintf(stderr, "fstat failed: %s\n", strerror(errno));
    return 1;
  };

  char* m = mmap(NULL, stat.st_size, PROT_READ, MAP_SHARED, f, 0);

  struct header h;
  struct body b;

  ssize_t pos = 0;
  char buf[89];
  while (pos < stat.st_size) {
    if (pos + 58 >= stat.st_size) {
      fprintf(stderr, "Unexpected end of file\n");
      return 1;
    };


    memcpy(buf, m + pos, 58);
    char* p = buf + 58;
    for (int i = 2; i-- > 0;) {
      *p = 0;
      p -= 15;
      h.i[i] = atoi(p--);
    };

    *p = 0;
    p -= 15;
    h.length = atoi(p--);

    *p = 0;
    p -= 9;
    h.f = atof(p);

    pos += 58;
    while (pos < stat.st_size && m[pos++] != '\n');

    for (int i = 0; i < h.length; ++i) {
      if (pos + 88 >= stat.st_size) {
        fprintf(stderr, "Unexpected end of file\n");
        return 1;
      };


      memcpy(buf, m + pos, 88);
      char* p = buf + 88;

      *p = 0;
      p -= 12;
      b.e = atof(p--);

      *p = 0;
      p -= 3;
      b.i = atoi(p--);

      for (int j = 7; j-- > 0;) {
        *p = 0;
        p -= 9;
        b.f[j] = atof(p--);
      };

      pos += 88;
      while (pos < stat.st_size && m[pos++] != '\n');
    };
  };

  print_header(&h);
  print_body(&b);

  return 0;
};
[fortran] > time ./mmap
    0.0900            1947          726626          566975
     0.6488    0.3638    0.3441    0.5092    0.9633    0.0133    0.6517  24   5.3600e-01

real    0m17.536s
user    0m17.485s
sys     0m0.050s

Фортран получился чуть-чуть медленнее C++ (за пределами погрешности, но очень близко). mmap вышел в 2.5 раза быстрее. Да, mmap выглядит ужасно, но его при желании можно переделать в конечный автомат и использовать почти как код на фортране. Если договориться, что числа всегда разделяются пробелами, то копирование в промежуточный буфер можно убрать и код ещё больше упростится. (Фортран умеет экономить на экспоненте и считывать 1.2-3 как 1.2e-3; в решении с буфером это можно учесть. Можно также написать свой парсер для чисел.)

Конечно, научные работники в массе своей с mmap-ом возиться не будут. Но тезис «I/O в фортране быстрее, чем в C++» пока не подтверждается.

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

Но тезис «I/O в фортране быстрее, чем в C++» пока не подтверждается.

Как он может подтвердиться, если потроха в операционке все равно написаны на Си или где-то местами даже на Си++? Это было ясно с самого начала. Фортран не в сферическом вакууме работает.

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

Как он может подтвердиться, если потроха в операционке все равно написаны на Си или где-то местами даже на Си++?

Так было понятно, что дело не в I/O операционки. А в том, как внутри программы происходит парсинг значений. Т.е. речь могла идти либо о тормознутости stdlib, либо о тормознутости самого алгоритма.

Например, в плюсах можно было бы сделать построчное чтение в std::string. Потом из std::string формировать std::istringstream, затем уже из istringstream делать парсинг.

Поэтому и хотелось от персонажа конкретики.

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

Решение eao197 на стандартных потоках C++:

Правильнее было бы сказать «по мотивам решения eao197»...

Принято.

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

в фортране есть свои особенности при работе с динамическими массивами

Не сразу обратил внимание. Это в примере на фортране переменная перезаписывается данными из «блока»?

(не помню, есть ли там нормальный realloc).

Мне известны такие (из темы обсуждения): Модули в C (комментарий)

Там 2 случая приведено для фортран 2003

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

Должно быть по совести MIT или BSD и очень веские причины использовать что-то более проприетарное. Это если наука финансируется из налогов.

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

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

в фортране есть свои особенности при работе с динамическими массивами

Не сразу обратил внимание. Это в примере на фортране переменная перезаписывается данными из «блока»?

Нет, это как раз то, что по твоей ссылке. Классический подход в фортране когда надо добавить памяти в массив --- это выделить новый массив, скопировать туда данные и удалить старый. Это менее оптимально, чем realloc, потому что realloc может и не двигать память если он может зарезервировать её дальше по тому же указателю; там могут быть и другие оптимизации, код realloc в glibc довольно нетривиальный. move_alloc тоже не позволяет изменить размер памяти, но он избавляет от необходимости возиться с двумя массивами в программе --- после удаления старого, новый можно переименовать и продолжать использовать ту же переменную. Мне кажется, я находил какое-то решение, аналогичное realloc, используя указатели (pointer) и какие-то нестандартные функции из gfortran, но сейчас уже не помню. Не исключено, что я просто делал обёртку для realloc из C и вызывал её в фортране.

Jini ★★
()

Вот что мне лично не нравится в фортране - так это уйобищный IO. А всё остальное нравится. Многие задачи конечно проще на питончике решить, но когда стоит вопрос производительности, тут фортрану нет равных. Любители c++ могут продолжать лезть на кактус и колоться.

yvv ★★☆
()
Ответ на: комментарий от Jini

fread.f(12): catastrophic error: Too many errors, exiting
compilation aborted for fread.f (code 1)

Такая проверка чтения не сработает.

Генерёшка тоже, как оказалось, написана с шоибками:

Fatal Error: Error count reached limit of 25.

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

Окей, нашёл у себя gfortran и смог скомпилировать герератор.

$ time ./ios_read
real 0m38.988s
user 0m38.656s
sys 0m0.352s

$ time ./mmap_read
real 0m16.660s
user 0m16.312s
sys 0m0.348s

И вот ваша фортрановская версия:

$ time ./fread
real 0m21.800s
user 0m21.516s
sys 0m0.288s

Не знаю только, зачем вы используете f08 и gfortran, если нужно f90 и ifort, но это мелочи.
Главный вывод - фортрановское стандартное I/O почти в 2 раза быстрее стандартного C/C++.
mmap версии просто повезло - она только читает. А вот, например, что нужно было делать:

input structure
b1
| t1: ev1 ev2 ev3 ... evn
| t2: ev1 ev2 ev3 ... evn
| ...
| tm: ev1 ev2 ev3 ... evn

output structure:
b1
| ev1: t1 t2 ... tm
| ev2: t1 t2 ... tm
| ...
| evn: t1 t2 ... tm

И со всеми добавками, уверяю, mmap не особо помогает и становится медленнее. Хотя, может вы напишете лучше меня.

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

Не, я имел ввиду, что в примере на фортране каждая строка тела перезаписывает переменную, а не добавляет данные к динамическому массиву (его там просто нет).

Частично, но не совсем. По моей ссылке в первом примере: создание временного массива, копирование в него, освобождение и создание старого массива с новыми размерностями, копирование из временного обратно, освобождение памяти под временный массив. То, что было в фортран 90.

Во втором примере уже отсутствует копирование обратно, там просто перенос указателя на новое место в памяти, где находится временный массив, и имя временного массива после этого уже не указывает на то же место автоматически. Фича Фортрана 2003.

В третьем примере для линейного массива конструктор пристыковыаает кусок массива к старому. Будет он выделять место под новый заново или скопирует из буфера, пристыковав к уже существующему месту в памяти, сложно сказать. Фича Фортрана 2003. Как получится. В том же C++ std::vector не гарантирует, что его элементы будут идти сплошным куском, емнип.

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

Бедняжку эдди всё ещё заставляют пользоваться перфокартами и стоять в очередях, в то время как всем остальным сотрудникам уже выдали персоналки.

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

В том же C++ std::vector не гарантирует, что его элементы будут идти сплошным куском, емнип.

Гарантирует. Так же, как и std::string.

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

Нашёл упоминание, что в 98 такое требование явно отсутствовало. Потом добавили. Раз сплошным это хорошо. Только не понял, если выполнить v.front, а затем v.back, обязательно ли элементы останутся лежать последовательно? Про то, что у вектора размер как правило больше его длины (резервирует память) я помню.

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

Только не понял, если выполнить v.front, а затем v.back, обязательно ли элементы останутся лежать последовательно?

Тут не понял. vector::front и vector::back — это ацессоры, они ничего не модифицируют. Может имелись в виду push_back?

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

Элементы всегда будут идти последовательно. Но при модифицирующих операциях итераторы (и, следовательно, ссылки, полученные через итераторы) инвалидируются. Т.е.:

std::vector<int> v = {1, 2, 3, 4};
int & first = v.front();
v.push_back(5); // Теперь first может указывать на мусор.
Доверять ссылкам/итераторам, и то, проявляя известную осторожность, можно только если предварительно был выполнен reserve. Например:
std::vector<int> v = {1, 2, 3, 4};
v.reserve(16);
int & first = v.front();
v.push_back(5);
assert(&first == &v.front()); // Тут должно быть все нормально.

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

Я так понимаю, фортран компилирует '(1X,F9.4,3(1X,I15))', а printf парсит форматную строку каждый раз в рантайме.

В принципе, в C++14/17 можно парсить строку в компайл-тайм (http://www.zverovich.net/2017/11/05/compile-time-format-strings.html), да хоть в фортрановском формате и, думаю, уделать его по производительности IO.

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

Не вдаваясь в подробности, просто напишу, что в фортране перемножение двух матриц будет записываться как A*B

Только лучше это делать через BLAS. Скорость перемножения гораздо выше (если большие матрицы).

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

Согласен. Если не сделают нормальную работу со строками произвольной длины и если не напишут высокоуровневые обёртки для всех основныхъ паков, народ окончательно свалит на Питон.

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

Это неверно. При таком перемножении матрицы будут помножены поэлементно, т.е. это аналог кода вида

do i = 1, size(A, DIM=1)
    do j = 1, size(A, DIM=2)
        C[i, j] = A[i, j] * B[i, j]
    enddo
enddo
Нормальное перемножение матриц как в линейной алгебре --- это
C = matmul(A, B)

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

Нормальное перемножение матриц как в линейной алгебре --- это
C = matmul(A, B)

Как так? В убогих крестах нормальное перемножение матриц — это A*B, а в богом данном научным сотрудникам Фортране это какой-то занюханый matmul(A,B)... ;)))

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

Новый Алгол

Algol W - другая ветка развития 60, стал Паскалем. (А это целое семейство языков, включая Modula, Oberon, обероноподобный Component Pascal и др.)

А возможности из «переусложнённого» Algol 68 сегодня кучей языков поддерживаются.

Если хочется похожего синтаксиса - это, внезапно, Bourne shell.

Где, кстати, проходит граница между новым языком и диалектом/версией стандарта? Сегодняшний Фортран имеет уже больше общего с другими языками, чем с «собой» шестидесятилетней давности. (Корабль Тессея вспоминается, ага.)

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

В крестах по умолчанию ничего не поддерживается. Там нужно делать переопределение операции «*». В Фортране эта операция уже определена и не только для матриц, но и для массивов произвольной размерности, она приводит к поэлементному умножению, как я показал выше. И это свойство используется очень часто. А операция именно матричного умножения --- это функция matmul. Тут просто следование традиции. Ничего ущербного тут нет: вот если бы «*» делало с одномерными массивами одно, с двумерными --- другое, а с трёхмерными --- третье, то это было бы действительно ужасно. А так оба функционала реализованы стандартными средствами языка: функция matmul является частью ядра и импортировать ничего не нужно, хотя возможно указать компилятору заменить стандартную реализацию реализацией из BLAS.

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

А операция именно матричного умножения --- это функция matmul. Тут просто следование традиции.

Какой-такой традиции? Это в какой традиции матричное умножение записывается как matmul?

Ну, это не говоря про то, что вы обратили внимание на количество смайликов.

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

Глянь библиотеку stringifor. Там как раз работа со строками упрощена.

Только сам никак ей не займусь. Ebuild бы доделать, чтобы и динамическую создавал либу помимо статики. А там можно и в дерево попробовать пропихнуть. Никак до компа не доберусь.

grem ★★★★★
()

Не понимаю, зачем нужно это замшелое дерьмо мамонта, если есть Go или на крайний случай Kotlin.

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

Как так? В убогих крестах нормальное перемножение матриц — это A*B, а в богом данном научным сотрудникам Фортране это какой-то занюханый matmul(A,B)... ;)))

В крестах нет перемножения матриц. Там даже нет стандартной библиотеки работы с матрицами. Нужно подключать библиотеки типа boost.

И второе. А ты уверено, что перегрузка операции * будет работать правильно, без расхода лишней памяти и быстро как matmul в фортране?

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

Посыпал голову пеплом. Как такое можно было забыть? :(

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

В крестах нет перемножения матриц.

Надо же, а мужики и не знают!

Там даже нет стандартной библиотеки работы с матрицами.

Что ж вы остановились на полдороги, давайте совсем уже сорвем покровы: там даже нет такого понятия, как матрица!

А ты уверено, что перегрузка операции * будет работать правильно, без расхода лишней памяти и быстро как matmul в фортране

Пилять, ну дебилизм.

Смайлики все видели в сообщении? Нет? А они там есть.

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

Мне кажется, что там уже всё встроено.

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

fread.f(12): catastrophic error: Too many errors, exiting
compilation aborted for fread.f (code 1)

Такая проверка чтения не сработает.

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

Окей, нашёл у себя gfortran и смог скомпилировать герератор.

Я эти результаты не воспроизвожу. Вот на другой машине:

fortran > time ./fortran
    0.6425            1473          868766          667616
     0.8809    0.0118    0.4070    0.4526    0.6876    0.4264    0.7441 119   0.6259E+00

real    0m28.477s
user    0m28.346s
sys     0m0.131s
fortran > time ./iostreams
0.6425 1473 868766 667616
 0.8809 0.0118 0.407 0.4526 0.6876 0.4264 0.7441 119 0.6259

real    0m27.212s
user    0m27.084s
sys     0m0.129s
fortran > time ./mmap
    0.6425            1473          868766          667616
     0.8809    0.0118    0.4070    0.4526    0.6876    0.4264    0.7441 119   6.2590e-01

real    0m10.811s
user    0m10.778s
sys     0m0.033s

Убедись, что ключи компиляции во всех случаях одинаковые. Или это ifort?

Не знаю только, зачем вы используете f08 и gfortran, если нужно f90 и ifort, но это мелочи.

Я не использую ifort потому что он несвободный, и потому что я уже давно не работаю с фортраном, у меня его просто нет.

И со всеми добавками, уверяю, mmap не особо помогает и становится медленнее.

Ну, как мы выяснили, считывание через mmap работает быстрее, не вижу причин, чтобы запись работала медленнее. Тем более, что здесь даже не надо парсить числа.

Хотя, может вы напишете лучше меня.

Не, я больше не хочу. Наш разговор начинает вызывать у меня приступы кошмаров с моей прошлой работы. Опять эти преобразования больших данных из одного текстового формата в другой. Это всё из-за нестандартизированности бинарного формата в фортране (интересно, это пофиксили в 2018?). Я рад, что я этим больше не занимаюсь.

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

Не, я имел ввиду, что в примере на фортране каждая строка тела перезаписывает переменную, а не добавляет данные к динамическому массиву (его там просто нет).

Тогда я не понимаю что ты спрашиваешь. При считывании заполняются как простые переменные, так и массивы, но память надо выделить заранее.

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

Кстати, если заменить циклы на GOTO, будет ещё быстрее.

Вот это очень странное утверждение, потому что циклы это и есть GOTO.

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

Должно быть по совести MIT или BSD [skip] если наука финансируется из налогов.

если финансируется из налогов, то должно быть гос или окологос проприетарное [skip] почему граждане одной страны должны брать на себя финансирование продукта для всех

Ну вот америкосы финансируют свои университетские поделия для всех, и ничего — впереди планеты всей.

С другой стороны, как ты сделаешь что-то доступным для всех граждан только одной страны? Сделать это можно для некоторых корпораций либо для тех же учёных, которые и финансирование будут получать, и продукт продавать за деньги, и совсем необязательно отечественным производителям.

Но продукт за деньги продавать смогут немногие, т. к. чтобы продать, его сначала надо довести до ума по всем пунктам (не только в плане новых идей и алгоритмов, но и менюшечки-рюшечки разные и т. д. и т. п.), на что у большинства учёных не хватит ни времени, ни ресурсов. А значит, поделия эти будут крутиться в одном отдельно взятом НИИ и умирать вместе с проектом, в котором они используются. А в соседнем НИИ будут писать точно такие же поделия с нуля.

За примерами далеко ходить не приходится. Когда в СССР для перестраховки засекречивали всё что можно, учёные и инженеры из разных НИИ и КБ просто дублировали работу друг друга.

Как-то так.

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

Кстати, если заменить циклы на GOTO, будет ещё быстрее.

Вот это очень странное утверждение, потому что циклы это и есть GOTO.

+100500

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

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

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