import std.string;
import std.algorithm;
import std.math;
import std.array;
import std.format;
import std.range;
import std.stdio;
import std.conv;
import std.container;

struct C { uint n; bool b; }

size_t[2][] fieldIndex;
C[][] field;
uint M, N;

pure bool isPrime(T)(T src){
    if(src <= 1)return false;
    else if(src < 4)return true;
    else if(!(src&1))return false;
    else if(((src+1)%6) && ((src-1)%6))return false;
    
    T root = cast(T)sqrt(cast(real)src) + 1;
    
    for(T i = 5; i < root; i += 6)
        if(!((src%i) && ((src)%(i+2))))
            return false;

    return true;
}


S dp(alias iterP, S)(S init)
{
    bool update = true;
    S[size_t] hash = [init.j : init];

    while(update){
        update = false;
        S[size_t] next;
        foreach(v; hash.byValue) if(v.isEnd) next[v.j] = v;
        foreach(v; hash.byValue){
            !v.isEnd && iterP!((t){
                if(auto p = t.j in next){
                    if(t > *p){ *p = t; update = true; }
                }else { next[t.j] = t; update = true; }
            })(v);
        }
        hash = next;
    }

    S s = hash.byValue.front;
    foreach(v; hash.byValue)
        if(v > s) s = v;

    return s;
}


struct S
{
    int i, j, c, n;
    int opCmp(ref const S s) const { return (c == s.c) ? (n - s.n) : (c - s.c); }
    bool opEquals(ref const S s) const { return i == s.i && j == s.j; }
    bool isEnd() const @property {
        return i == 1000 || (
            (j == 0 || field[i+1][j-1].n > M) && (j == 1000 || field[i+1][j+1].n > M) && (field[i+1][j].n > M)
        );
    }
}


void iterPImpl(alias fn)(S s)
{
    static S make(S s, uint i, uint j) { return S(i, j, field[i][j].b ? s.c+1 : s.c, field[i][j].b ? field[i][j].n : s.n); }
    if(s.j != 0 && field[s.i+1][s.j-1].n <= M) fn(make(s, s.i+1, s.j-1));
    if(field[s.i+1][s.j].n <= M) fn(make(s, s.i+1, s.j));
    if(s.j != 1000 && field[s.i+1][s.j+1].n <= M) fn(make(s, s.i+1, s.j+1));
}


void main()
{
    field = new C[][](1001, 1001);

    {
        uint ci = 500, cj = 500, step = 1, n;
        fieldIndex ~= [0, 0];
        while(1){
            if(step == 1001) break;
            foreach(i; 0 .. step){
                ++n;
                field[ci][cj] = C(n, isPrime(n));
                fieldIndex ~= [ci, cj];
                ++cj;
            }
            foreach(i; 0 .. step){
                ++n;
                field[ci][cj] = C(n, isPrime(n));
                fieldIndex ~= [ci, cj];
                --ci;
            }
            ++step;
            foreach(i; 0 .. step){
                ++n;
                field[ci][cj] = C(n, isPrime(n));
                fieldIndex ~= [ci, cj];
                --cj;
            }
            foreach(i; 0 .. step){
                ++n;
                field[ci][cj] = C(n, isPrime(n));
                fieldIndex ~= [ci, cj];
                ++ci;
            }
            ++step;
        }
    }

    while(1){
        auto mn = readln().chomp().split().map!(to!uint);
        M = mn[0];
        N = mn[1];
        if(!M) return;
        //writeln(fieldIndex[N]);

        auto idx = fieldIndex[N];
        bool isP = isPrime(N);
        auto s = dp!iterPImpl(S(cast(uint)idx[0], cast(uint)idx[1], isP ? 1 : 0, isP ? N : 0));
        writefln("%s %s", s.c, s.n);
    }
}