Операциите с плаваща запетая са по-бавни, когато се използват малки стойности?

Имам следната проста програма, която умножава две различни числа с плаваща запетая много пъти. Както можете да видите, едно от числата е много малко. Когато изчислих времето за изпълнение на двете умножения, бях изненадан, че малкото число отнема много повече време от другото. Изглежда, че работата с малки двойки е по-бавна... Някой знае ли какво се случва?

public static void main(String[] args) throws Exception
{
    long iterations = 10000000;
    double result;
    double number = 0.1D;
    double numberA = Double.MIN_VALUE;
    double numberB = 0.0008D;

    long startTime, endTime,elapsedTime;


    //Multiply numberA
    startTime = System.currentTimeMillis();

    for(int i=0; i < iterations; i++)
        result = number * numberA;

    endTime = System.currentTimeMillis();
    elapsedTime = endTime - startTime;

    System.out.println("Number A) Time elapsed: " + elapsedTime + " ms");

    //Multiply numberB
    startTime = System.currentTimeMillis();
    for(int i=0; i < iterations; i++)
        result = number * numberB;

    endTime = System.currentTimeMillis();
    elapsedTime = endTime - startTime;

    System.out.println("Number B) Time elapsed: " + elapsedTime + " ms");
}

Резултат:

Number A) Time elapsed: 3546 ms
Number B) Time elapsed: 110 ms

Платформа Windows, Java 1.6.0_07

Благодаря, Диего


person Community    schedule 14.07.2009    source източник


Отговори (4)


Когато работите близо до минималното представяне на стойност с плаваща запетая IEEE 758, е вероятно да получите резултати, които са "денормално". Те понякога, макар и не винаги, се обработват по-бавно. Подозирам, че JVM ги обработва по някакъв начин специално, вместо да разчита на чиста хардуерна поддръжка, което води до известно влошаване на производителността.

person Tim Sylvester    schedule 14.07.2009

Предполагам, че компилаторът е заменен

number * numberB;

с точната му стойност, тъй като number и numberB са постоянни стойности, за които компилаторът знае, че не са се променили до този момент. Въпреки това, numberA не е постоянна стойност (стойността му е специфична за платформата) и така че трябва действително да правите изчислението всеки път. Опитайте да замените Double.MIN_VALUE с действителната му стойност и вижте дали се представят по подобен начин.

person Nick Lewis    schedule 14.07.2009
comment
Не, замених го с 4.9E-324 и получи същите резултати... Благодаря!! - person ; 14.07.2009
comment
Направете го с 0.0000008 и започнете да увеличавате нулите преди 8. - person akarnokd; 14.07.2009
comment
Хм, също така напълно пропуснах факта, че умножавате епсилон по число, по-малко от 1. Това почти сигурно има нещо общо с това! - person Nick Lewis; 14.07.2009
comment
Имам предвид начертайте хистограма въз основа на логаритмично мащабирани тестови стойности. - person akarnokd; 14.07.2009
comment
Пусках го в Ubuntu 8.04 и получавам: Номер A) Изминало време: 44 ms Номер B) Изминало време: 49 ms Има нещо странно с Windows JVM... - person ; 14.07.2009

Възможно е да въведете обхвата на "денормалните" числа (вижте формат IEEE754). Обработването на тези числа може да изисква повече време в модула с плаваща запетая.

person Eric Bainville    schedule 14.07.2009
comment
Пусках го в Ubuntu 8.04 и получавам: Номер A) Изминало време: 44 ms Номер B) Изминало време: 49 ms Има нещо странно с Windows JVM... - person ; 14.07.2009

Изглежда, че е грешка в Windows JVM

person Community    schedule 15.07.2009