#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <algorithm>
#include <sstream>
#include <iostream>
#include <cassert>
using namespace std;

typedef long long ll;

#define REP(i, n) for (int i = 0; i < (int)(n); ++i)
#define FOR(i, a, b) for (int i = (a); i < (int)(b); ++i)
#define FOREQ(i, a, b) for (int i = (a); i <= (int)(b); ++i)
#define DEC(i, k) for (int i = (k); i >= 0; --i)
#define FORIT(i, c) for (__tyoeof((c).begin()) i = (c).begin(); i != (c).end(); ++i)
#define SZ(v) (int)((v).size())
#define MEMSET(v, h) memset((v), (h), sizeof(v))
#define FIND(m, w) ((m).find(w) != (m).end())
#define ALL(c) (c).begin(), (c).end()

int m, n;
double probability[20][20];
double dp[2][(1 << 16) + 10];
double win[2][(1 << 16) + 10][20];

inline int bsf(int x) {
  __asm__("bsf %1, %0;" :"=r"(x) :"r"(x));
  return x;
}

int main() {
  scanf("%d %d", &m, &n);
  MEMSET(probability, 0);
  REP(cat, m) {
    REP(room, n) {
      scanf("%lf", &probability[cat][room]);
    }
  }

  MEMSET(dp, 0);
  MEMSET(win, -1);
  REP(S, 1 << m) {
    dp[n % 2][S] = 1.0;
  }
  REP(S, 1 << m) {
    REP(c, m) {
      win[n % 2][S][c] = 1.0;
    }
  }

  for (int i = n-1; i >= 0; --i) {
    int curr = i % 2;
    int prev = 1 - curr;
    FOR(S, 0, 1 << m) {
      dp[curr][S] = 0.0;
      REP(c, m) {
        if (S & (1 << c)) {
          dp[curr][S] = max(dp[curr][S], win[curr][S^(1<<c)][c]);
        }
      }
      REP(c, m) {
        if (S != 0) {
          win[curr][S][c] = probability[c][i] * win[prev][S][c]
            + (1.0 - probability[c][i]) * dp[curr][S];
        } else {
          win[curr][S][c] = probability[c][i] * win[prev][S][c];
        }
      }
    }
  }

  printf("%.9lf\n", dp[0][(1 << m) - 1]);
}