C: сжатие последовательности ДНК в двоичную - PullRequest
0 голосов
/ 05 декабря 2018

Привет, я пытаюсь понять, как получить функцию для преобразования кода ДНК в двоичные биты, нужно, чтобы она выглядела так: ACGTT -> XXXXXX11 11100100 справа налево для A = 0 C = 1 G = 2Т = 3.теперь я думал сделать это символом, а затем переместить его на >> 2 из функции, но я не могу понять саму функцию ... я попытался вот так, и таким образом она возвращает NULL.

char CompressChar(char c){
char temp[8]="XXXXXXXX";
if (c=='A'){
 temp[7] = '0';
 temp[6] = '0';
}
if (c=='C'){
    temp[7]='1';
    temp[6]='0';
}
if(c=='G'){

    temp[7]='0';
    temp[6]='1';
}

if(c=='T'){
   temp[7]='1';
   temp[6]='1';
}
return temp;

}

1 Ответ

0 голосов
/ 05 декабря 2018

Насколько я понимаю, вы хотите, чтобы каждая буква (они называются нуклеотидом iirc?) Представляла 2 двоичные цифры.

Начнем с того, что char temp[8]="XXXXXXXX"; не имеет смысла, поскольку строки в C завершаются нулеми вы не выделяете место для нулевого терминатора, должно быть [8+1].И вам нужно 16 бит, а не 8.

Ваша функция возвращает char, что неверно, вам нужно вернуть целый массив.Это необходимо сделать с помощью параметра, поскольку вы не можете возвращать массивы в C. Не можете вернуть указатель на локальные данные, поэтому было бы лучше оставить выделение для вызывающей стороны.В любом случае ... очистите эту функцию.

Кроме того, нет смысла преобразовывать это в "двоичную строку".Лучше преобразовать его в двоичное число, а затем при необходимости преобразовать это число в строку.

Преобразование, включающее «обратный порядок», можно затем выполнить следующим образом:

uint16_t dna_to_bin (const char* str)
{
  uint16_t result = 0;
  size_t i;

  for(i=0; i<16; i+=2)       // loop over bits in the resulting binary number
  {
    typedef enum             // local enum just for readability
    {
      A = 0,
      C = 1,
      G = 2,
      T = 3,
    } dna_t;
    dna_t type=0;            // default is 0 if nothing to decode

    if(*str != '\0')         // keep decoding string until reaching the end
    {
      switch(*str)
      {
        case 'A':     type = A; break;
        case 'C':     type = C; break;
        case 'G':     type = G; break;
        case 'T':     type = T; break;
      }
      str++;
    }

    result |= (uint16_t)type << i; // store data at correct position in the result
  }

  return result;
}

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

#include <stdint.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdbool.h>

uint16_t dna_to_bin (const char* str)
{
  uint16_t result = 0;
  size_t i;

  for(i=0; i<16; i+=2)
  {
    typedef enum
    {
      A = 0,
      C = 1,
      G = 2,
      T = 3,
    } dna_t;
    dna_t type=0;

    if(*str != '\0')
    {
      switch(*str)
      {
        case 'A':     type = A; break;
        case 'C':     type = C; break;
        case 'G':     type = G; break;
        case 'T':     type = T; break;
      }
      str++;
    }
    result |= (uint16_t)type << i;
  }

  return result;
}


void print_bin (uint16_t bin)
{
  bool remove_zeroes = true;

  for(size_t i=0; i<16; i++)
  {
    uint16_t mask = 1u << (16-1-i);
    uint16_t bit = bin & mask;

    if(bit == 0)
    {
      if(!remove_zeroes)
      {
        printf("0");
      }
    }
    else
    {
      remove_zeroes = false;
      printf("1");
    }
  }
}


int main (void)
{
  const char STR_DNA[] = "ACGTT";
  uint16_t bin = dna_to_bin(STR_DNA);

  puts(STR_DNA);
  printf("Hex: %.4"PRIX16 "\n", bin);
  printf("Bin: ");
  print_bin(bin);

  return (0);
}

Вывод:

ACGTT
Hex: 03E4
Bin: 1111100100
...