Вычесть необработанные файлы с плавающей запятой поэлементно с помощью скрипта?

У меня есть два файла, которые представляют собой необработанные последовательности 32-битных значений с плавающей запятой с прямым порядком байтов (без сумасшедших значений, таких как бесконечность, NaN, денормалы и т. д.), и я хочу создать их поэлементную разницу в третьем файле.

Теперь я могу написать небольшую утилиту, чтобы сделать это с относительной эффективностью практически на любом скомпилированном языке, но мне было интересно, смогу ли я добиться того же с помощью короткого скрипта, используя обычные инструменты. Моя интуиция говорит нет, так как это довольно нетекстовая работа, но, возможно, я ошибаюсь.


person einpoklum    schedule 01.10.2020    source источник
comment
Поскольку оболочка POSIX не имеет никакой арифметики, не говоря уже о арифметике с плавающей запятой, это не совсем правильный инструмент для работы. При условии, что вы можете преобразовать необработанные данные в строковое представление чисел с плавающей запятой, вы можете использовать такой инструмент, как bc для арифметики. Является ли двоичный формат для чисел с плавающей запятой IEEE float 32, и знаете ли вы, как они хранятся — с прямым порядком байтов или прямым порядком байтов?   -  person user1934428    schedule 01.10.2020
comment
@ user1934428: Они с прямым порядком байтов. Я полагаю, что мог бы пройти строковое представление с чем-то вроде od и большим количеством bc, но это, вероятно, было бы довольно медленным.   -  person einpoklum    schedule 02.10.2020
comment
Если скорость действительно проблема, почему вы вообще рассматриваете некомпилируемый язык? Если вы настаиваете на том, чтобы делать это только с оболочкой POSIX (а не с Ruby или Perl (как предложил Шон в своем ответе) или что-то в этом роде), я бы разделил задачу на две подзадачи: Превращение двоичного представления в строку , а затем обработать строку в контексте оболочки. Если скорость важна, самым простым способом, вероятно, будет программа на языке C.   -  person user1934428    schedule 02.10.2020
comment
@ user1934428: 1. Например, я могу быть в системе, где не установлен компилятор. Кроме того, быть проблемой на самом деле не бинарная вещь. А может мне просто интересно. 2. Я не говорил только оболочку POSIX...   -  person einpoklum    schedule 02.10.2020
comment
@ user1934428: Я сказал общие инструменты. Я удалю тег.   -  person einpoklum    schedule 04.10.2020


Ответы (1)


Быстрый perl скрипт, который это сделает (принимает два файла в качестве аргументов командной строки, записывает в стандартный вывод):

#!/usr/bin/env perl
use warnings;
use strict;

open my $file1, "<:raw", $ARGV[0] or die "Unable to open $ARGV[0]: $!\n";
open my $file2, "<:raw", $ARGV[1] or die "Unable to open $ARGV[1]: $!\n";
binmode STDOUT, ":raw";

while (read($file1, my $s1, 4) == 4 && read($file2, my $s2, 4) == 4) {
    my $f1 = unpack "f<", $s1;
    my $f2 = unpack "f<", $s2;
    print pack("f<", $f1 - $f2);
}

Ключевым моментом здесь является pack и формат "f<" unpack для работы с явным прямым порядком байтов одинарной точности. float (в собственном формате хост-систем, обычно IEEE754 на большинстве типичных аппаратных средств).

person Shawn    schedule 01.10.2020
comment
Драгоценный эклектичный список мусора спешит на помощь :-) Могу ли я ожидать, что это будет достаточно быстро, чтобы обработать изображение приличного размера (скажем, миллион чисел с плавающей запятой и выше)? - person einpoklum; 02.10.2020
comment
@einpoklum Запускается менее чем за секунду для миллиона поплавков на моем десятилетнем компьютере в быстром тесте только что. - person Shawn; 02.10.2020