Суммируйте большие числа и распечатайте результат со всеми десятичными знаками для указанного вопроса при использовании массивов awk.

Он работает с интернет-кабелем?

Если да, сделайте это:

    echo 'deb http://ftp.debian.org/debian/ stretch main contrib non-free' >/etc/apt/sources.list
    apt-get update
    apt-get install firmware-realtek 

Чтобы установить сетевые драйверы...

Перезагрузите компьютер и повторите попытку поиска сетей Wi-Fi.

Если у вас нет возможности подключиться к Интернету по кабелю, загрузите пакет отсюда :http://ftp.us.debian.org/debian/pool/non-free/f/firmware-nonfree/firmware-realtek_20161130-4_all.deb

Сохраните на флешке, откройте флешку на машине с Debian, щелкните правой кнопкой мыши в «папке» флешки, откройте в терминале, установите с помощью:

 dpkg -i firmware-realtek_20161130-4_all.deb

Перезагрузите компьютер и повторите попытку поиска сетей Wi-Fi.

1
17.05.2020, 02:08
2 ответа

Не принимая во внимание вашу проблему с большими числами, я бы написал awkпрограмму примерно так:

BEGIN {
        FS = "\\|~\\^"
        OFS= "|~^"
}

$1 == "H" {
        header = $0
}

$1 == "R" {
        name = $3
        sub("T.*", "", name)

        sum[name] += $4
        cnt[name] += 1

        if (cnt[name] == 1)
                print header >name ".txt"

        print >name ".txt"
}

$1 == "T" {
        for (name in sum)
                print $1, $2, cnt[name], $4, sum[name] >name ".txt"
}

Для удобства я установил разделитель полей вывода OFSна |~^. Это позволяет мне не беспокоиться о вставке его между полями, которые я вывожу. В качестве разделителя полей для ввода FSиспользуется регулярное выражение, соответствующее этой строке.

Затем у меня есть три основных блока кода:

  1. Один для разбора строки H. Предполагается, что существует только один из них и что он возникает в начале. Это просто сохраняет строку заголовка в переменной header.

  2. Один для разбора строк R. Каждая запись содержит дату, которая должна использоваться в качестве имени выходного файла в 3-м поле. Это анализируется так же, как и вы. Сумма за эту дату накапливается, а также увеличивается счетчик.

    Если счетчик равен единице, то есть если мы впервые видим эту конкретную дату, мы записываем заголовок в выходной файл, связанный с этой датой. Затем мы записываем текущую запись в файл.

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

Для поддержки произвольно больших чисел (вы говорите в другом месте , что у вас есть числа, для хранения которых требуется более 100 бит, и поэтому целое число вawk)будет переполнено, мы используем калькулятор произвольной точности bcкак "сопроцесс" (своего рода вычислительная служба ). Строка с надписью sum[name] += $4заменена на

if (sum[name] == "") sum[name] = 0
printf "%s + %s\n", sum[name], $4 |& "bc"
"bc" |& getline sum[name]

Для этого требуется GNU awk(, доступный для большинства систем Unix, так или иначе ).

Это сначала инициализирует сумму для текущей даты нулем, если для этой даты еще нет суммы. Мы делаем это, потому что нам нужно поставить от 0до bcдля начальной суммы.

Затем мы печатаем выражение, которое bcдолжно вычислить, используя специальный |&конвейер GNUawk-для записи в сопроцесс. Утилита bc, которая будет запускаться и работать параллельно с нашим сценарием awk, выполняет вычисления, а следующая getlineсчитывает вывод из bcиз другого канала |&прямо в sum[name]..

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

Для заданных данных будут созданы следующие два файла:

$ cat 2019-03-05.txt
H|~^20200425|~^abcd|~^sum
R|~^abc|~^2019-03-05T12:33:52.27|~^105603.042|~^2018-10-23T12:33:52.27|~^aus
R|~^abc|~^2019-03-05T12:33:52.27|~^2054.026|~^2018-10-24T12:33:52.27|~^usa
R|~^abc|~^2019-03-05T12:33:52.27|~^30.00|~^2018-08-05T12:33:52.27|~^ddd
R|~^abc|~^2019-03-05T12:33:52.27|~^20.00|~^2018-07-23T12:33:52.27|~^audg
T|~^20200425|~^4|~^xxx|~^107707.068
$ cat 2019-03-06.txt
H|~^20200425|~^abcd|~^sum
R|~^abc|~^2019-03-06T12:33:52.27|~^123562388.23456|~^2018-04-12T12:33:52.27|~^hhh
R|~^abc|~^2019-03-06T12:33:52.27|~^10.00|~^2018-09-11T12:33:52.27|~^virginia
R|~^abc|~^2019-03-06T12:33:52.27|~^15.03|~^2018-10-23T12:33:52.27|~^jjj
R|~^abc|~^2019-03-06T12:33:52.27|~^10.04|~^2018-04-08T12:33:52.27|~^jj
T|~^20200425|~^4|~^xxx|~^123562423.30456
1
28.04.2021, 23:13

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

Вы уже задавали вопрос о суммировании многих чисел и получении неточного ответа в прошлом. Этот вопрос очень похож на этот другой вопрос Почему существует разница между этими двумя командами суммирования? .

Файл из этого вопроса весил 20 мегабайт и содержал более 700 тысяч строк.
Вы заявили, что ваши файлы находятся в порядке Размер файла составляет от 500 до 600 МБ . Это увеличит количество строк до 10 миллионов строк.

Проблема в том, что цифры для добавления:

  • может варьироваться в широких пределах :от 3 цифр 12.8до 28 цифр 1245637.34526234567299999999.

  • Сложение 28-значных чисел 10 миллионов раз должно потребовать 28 + 7 = 35 цифр. И это при условии, что цифры не все десятичные или целые числа. Если это возможно, мы говорим о 70 цифрах (35 целых + 35 десятичных дробях ).

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

Решением вашей проблемы может быть использование GNU awk с более длинным числом цифр. По умолчанию в awk числа с плавающей запятой используют 53-битную мантиссу, подходящую только для 15 цифр.

Если вы используете GNU AWK, скомпилированный с помощью MPFR (Multiple Precision Floating -Point Reliably )и GMP (GNU Multiple Precision Arithmetic Library ), результат ее --текст версии должен включать эту информацию (executeawk --version). В этом случае вы можете использовать больше битов. Чтобы иметь возможность хранить 40-значные числа с плавающей запятой (35 цифр, рассчитанных выше + некоторый запас безопасности ), вам понадобится:

b = ceil(d log2(10)) + 1

b = ceil( 40 * 3.321928 ) + 1 = 133 + 1 = 134 binary digits (bits)

Таким образом, вызов awk должен быть:

 awk -M -v PREC=134 

Предупреждение :Использование большего количества цифр замедляет работу программы.

И по-прежнему использовать ту же программу awk

awk -M -v PREC=134 '

     BEGIN  { FS="\\|~\\^"; OFS="|~^" }
     $1=="H"{ header=$0; hdr=$2 }
     $1=="R"{
              t=gensub(/-/, "","g",$3)
              file=gensub(/T.*/,"",1,t);
              sum[file]+=$4
              if(count[file]==0){ print header >file }
              count[file]++
              print $0 >>file
            }
     END    {
              for( i in sum ){
                  printf "T %s %10d xxx %45.25f",hdr,count[i],"xxx",sum[i] >> i;
                  close(i)
                  }
            }
' "inputfile"

Для справки :Вы задавали почти один и тот же вопрос снова и снова:

1
28.04.2021, 23:13

Теги

Похожие вопросы