Frage

Ich versuche, doppelt geprüft zu verwenden Sperren eine Reihe von Binomialkoeffizienten zu halten, aber ich habe kürzlich gelesen, dass doppelt überprüft Verriegelung nicht funktioniert. Der Wirkungsgrad ist extrem wichtig, so flüchtig verwendet, ist keine Option, wenn es nur innerhalb der bedingten Anweisungen ist. Ich kann nicht sehen, wie man eine statische Klasse mit einem Singleton-Objekt zu verwenden (dieser Teil eines Rahmens ist, und ich weiß nicht, was Arten von Zahl Menschen die Funktion für verwenden müssen, so kann ich nicht erraten, was die maximalen gewählter Wert wird oder ob die Funktion überhaupt verwendet werden). Das einzige, was ich denken kann, ist alles nicht statisch und darauf bestehen, zu machen, dass jeder Thread, dass der Bedarf ein diese Methode instantiate zu verwenden Objekt mit einem eigenen Array auswählen. Es scheint so, dass sollte nicht notwendig sein.

public static final class Util{
/**
 * Static array of nCr values
 */
public static long[][] nCr_arr;

/**
 * Calculate binomial coefficient (n k)
 * 
 * @param n
 *            n
 * @param k
 *            k
 * @return n choose k
 */
public static long nCr(int n, int k) {
    if (k < 0)
        throw new ArithmeticException("Cannot choose a negative number");
    if (n < 0) {
        if (k % 2 == 0)
            return nCr(-n + k - 1, k);
        else
            return -nCr(-n + k - 1, k);
    }
    if (k > n)
        return 0;
    if (k > n / 2)
        k = n - k;
    if (nCr_arr == null) {
        synchronized (Util.class) {
            if (nCr_arr == null)
                nCr_arr = new long[n + 1][];
        }
    }
    if (nCr_arr.length <= n) {
        synchronized (Util.class) {
            if (nCr_arr.length <= n) {
                long[][] newNCR = new long[n + 1][];
                System.arraycopy(nCr_arr, 0, newNCR, 0, nCr_arr.length);
                nCr_arr = newNCR;
            }
        }
    }
    if (nCr_arr[n] == null) {
        synchronized (Util.class) {
            if (nCr_arr[n] == null)
                nCr_arr[n] = new long[k + 1];
        }
    }
    if (nCr_arr[n].length <= k) {
        synchronized (Util.class) {
            if (nCr_arr[n].length <= k) {
                long[] newNCR = new long[k + 1];
                System.arraycopy(nCr_arr[n], 0, newNCR, 0,
                        nCr_arr[n].length);
                nCr_arr[n] = newNCR;
            }
        }
    }
    if (nCr_arr[n][k] == 0) {
        if (k == 0)
            nCr_arr[n][k] = 1;
        else
            nCr_arr[n][k] = nCr(n, k - 1) * (n - (k - 1)) / k;
    }
    return nCr_arr[n][k];
}
}
War es hilfreich?

Lösung 6

ich am Ende einfach nicht statisch zu machen. Wenn ein Thread Bedürfnisse nCr Werte zu erhalten, erstellt es eine neue Koeffizient Objekt und hält sich an sie.

Andere Tipps

Nun, könnte man immer doppelt vermeiden geprüft Verriegelung durch den Code ändert:

if (nCr_arr == null) {
    synchronized (Util.class) {
        if (nCr_arr == null)
            nCr_arr = new long[n + 1][];
    }
}

folgt aus:

synchronized (Util.class) {
    if (nCr_arr == null)
        nCr_arr = new long[n + 1][];
}

ich wette, die Auswirkungen auf die Leistung würde sehr klein sein.

Sind Sie sicher, dass Sie diese optimieren müssen? Haben Sie Ausführen von Code profiliert und fanden die einzelne Sperre ist zu teuer?

oder neu schreiben Ihren Code neue Java Concurrency-API http://download.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/ReadWriteLock.html und erhält Schreibsperre nur, wenn wirklich benötigt wird.

Da Sie verwenden diese in einem sehr leistungskritischen Teil des Codes, empfehle ich die verzögerte Initialisierung Idee Notwasserung, weil es mehrere zusätzliche Vergleiche erfordert für jeden Zugriff auf einen Koeffizienten durchgeführt werden.

Stattdessen würde ich den Benutzer Ihrer Bibliothek erfordert manuell festlegen, wie viele Koeffizienten sie bei der Initialisierung benötigt. Alternativ würde ich precompute mehr als der Benutzer jedes wahrscheinlich notwendig ist, -. Sie alle NCK für n passen <1000 in 1 MB Speicher

PS: Darf ich vorschlagen, dass Sie die rekursive Formel verwenden, um einen Koeffizienten zu berechnen

?
c[n][k] = c[n-1][k-1] + c[n-1][k]

Es wird nicht viel aus, aber warum Gebrauch komplizierte Formel, wenn Sie benötigen Pascals Dreieck

I sieht aus wie Sie einen einen Cache der Ergebnisse auf, wie sie berechnet werden, so dass Sie eine gleichzeitige Karte verwenden könnte, die Ergebnisse zu halten durch den Bau eines Schlüssel, verbindet die zwei int-Werte in eine einzige lange.

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

public final class Util {
    /**
     * Static array of nCr values
     */
    private static final ConcurrentMap<Long,Long> CACHE = 
        new ConcurrentHashMap<Long, Long>();

    /**
     * Calculate binomial coefficient (n k)
     * 
     * @param n
     *            n
     * @param k
     *            k
     * @return n choose k
     */
    public static long nCr(int n, int k) {
        if (k < 0)
            throw new ArithmeticException("Cannot choose a negative number");
        if (n < 0) {
            if (k % 2 == 0)
                return nCr(-n + k - 1, k);
            else
                return -nCr(-n + k - 1, k);
        }

        if (k > n)
            return 0;
        if (k > n / 2)
            k = n - k;

        final long key = (n << 32L) + k;

        Long value = CACHE.get(key);
        if (value != null) {
            return value.longValue();
        } 

        long result;

        if (k == 0)
            result = 1;
        else
            result = nCr(n, k - 1) * (n - (k - 1)) / k;

        CACHE.put(key, result);

        return result;
    }
}

Der ursprüngliche Code hat viel zu viele Rennbedingungen. Für den Anfang können nicht Sie nicht flüchtigen nCr_arr und die Hoffnung auf doppelte Kontrolle Idiom zur Arbeit aktualisieren. Deklarieren besiegt er flüchtig völlig den Zweck des Cache irgendwie. Die richtige Code sollte nicht synchron überhaupt verwenden, aber CAS.

CHM ist eine sehr schlechte Wahl auch hier (auch nicht CHM nicht gut skalieren). (Sie sich auch lange als Schlüssel nicht sehr gut b / c der ist, wie valueOf funktioniert, ist es nicht richtig von Hotspot inlined werden kann, da es nicht immer ein Objekt erstellen und Endwert Feld nicht hilft entweder)

Wenn jemand (noch) interessiert, wie Sie den Code zu tun, eine Notiz fallen. Prost

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top