#include <iostream>
#include <sstream>
#include <string>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <cassert>

using namespace std;

#define FOR(i,k,n) for(int i=(k); i<(int)(n); ++i)
#define REP(i,n) FOR(i,0,n)
#define FORIT(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();++i)

template<class T> void debug(T begin, T end){ for(T i = begin; i != end; ++i) cerr<<*i<<" "; cerr<<endl; }
inline bool valid(int x, int y, int W, int H){ return (x >= 0 && y >= 0 && x < W && y < H); }

typedef long long ll;
const int INF = 100000000;
const double EPS = 1e-8;
const int MOD = 1000000007;
int dx[8] = {1, 0, -1, 0, 1, -1, -1, 1};
int dy[8] = {0, 1, 0, -1, 1, 1, -1, -1};

int main(){
  int M, N;
  cin >> M >> N;
  // M - cat N - room
  static double pos[16][17];
  REP(i, M) REP(j, N) cin >> pos[i][j];

  static double dp[1 << 16][17];
  REP(S, 1 << M) REP(u, N + 1) dp[S][N] = (u == N) ? 1.0 : 0.0;

  for(int u = N - 1; u >= 0; u--){
    for(int S = 0; S < 1 << M; S++){
      for(int i = 0; i < M; i++) if(S >> i & 1){
        double p = 1.0;
        double npos = 0.0;
        for(int v = u; v <= N; v++){
          npos += dp[S & ~(1 << i)][v] * p * (1.0 - pos[i][v]);
          p *= pos[i][v];
        }
        dp[S][u] = max(dp[S][u], npos);
      }
    }
  }

  printf("%.12f\n", dp[(1 << M) - 1][0]);
  return 0;
}