Управление и сравнение плавающих точек в Java

Вы не можете вызывать предварительно подписанный URL-адрес напрямую через браузер.

Вам необходимо передавать заголовки в запросе

  1. x-amz-server-side-encryption- алгоритм клиента

  2. x-amz-шифрование на стороне сервера-ключ клиента

  3. шифрование на стороне сервера x-amz -Customer-key-MD5

Пожалуйста, проверьте документ для получения дополнительной информации https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerSideEncryptionCustomerKeys.html

При использовании предварительно назначенного URL-адреса для загрузки нового объекта, извлечения существующего объекта или извлечения только метаданных объекта необходимо предоставить все заголовки шифрования в клиентском приложении.

blockquote>

Пожалуйста, проверьте пример кода, вызывающего подписанный URL через библиотеку Unirest https://github.com/pavanpawar4591/s3signurlwith-sse-c

public static void getPreSignedURL() throws URISyntaxException {
        java.util.Date expiration = new java.util.Date();
        long expTimeMillis = expiration.getTime();
        expTimeMillis += 1000 * 60 * 60;
        expiration.setTime(expTimeMillis);

        System.out.println("Generating pre-signed URL.");
        GeneratePresignedUrlRequest generatePresignedUrlRequest = new GeneratePresignedUrlRequest(bucketName, keyName)
                .withMethod(HttpMethod.GET).withExpiration(expiration).withSSECustomerKey(SSE_KEY);

        // generatePresignedUrlRequest.setContentType("video/mp4");
        generatePresignedUrlRequest.setSSECustomerKeyAlgorithm(SSEAlgorithm.AES256);

        URL url = s3Client.generatePresignedUrl(generatePresignedUrlRequest);

        System.out.println("Pre-Signed URL: " + url.toURI() + " With key: " + SSE_KEY);

        System.out.println("------------------------------");
        //https://aws.amazon.com/blogs/developer/generating-amazon-s3-pre-signed-urls-with-sse-c-part-4/ 
        // refer to above doc
        try {
            HttpResponse response = Unirest.get(url.toURI().toString())
                    .header(Headers.SERVER_SIDE_ENCRYPTION_CUSTOMER_ALGORITHM, SSEAlgorithm.AES256.getAlgorithm())
                    .header(Headers.SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY, Base64.encodeAsString(SECRET_KEY.getEncoded()))
                    .header(Headers.SERVER_SIDE_ENCRYPTION_CUSTOMER_KEY_MD5,
                            Md5Utils.md5AsBase64(SECRET_KEY.getEncoded()))
                    .header("cache-control", "no-cache").header("postman-token", "d3453c38-1b59-a12e-fd97-dbe2150eadf5")
                    .asString();

            System.out.println(response.getStatus());
            System.out.println(response.getStatusText());
            System.out.println(response.getBody());
        } catch (UnirestException e) {

            e.printStackTrace();
        }

    }

10
задан Eric Leschinski 14 June 2015 в 23:18
поделиться

7 ответов

Округление является плохой идеей. Используйте BigDecimal и установите, это - точность по мере необходимости. Как:

public static void main(String... args) {
    float a = 1.2f;
    float b = 3.0f;
    float c = a * b;
    BigDecimal a2 = BigDecimal.valueOf(a);
    BigDecimal b2 = BigDecimal.valueOf(b);
    BigDecimal c2 = a2.multiply(b2);
    BigDecimal a3 = a2.setScale(2, RoundingMode.HALF_UP);
    BigDecimal b3 = b2.setScale(2, RoundingMode.HALF_UP);
    BigDecimal c3 = a3.multiply(b3);
    BigDecimal c4 = a3.multiply(b3).setScale(2, RoundingMode.HALF_UP);

    System.out.println(c); // 3.6000001
    System.out.println(c2); // 3.60000014305114740
    System.out.println(c3); // 3.6000
    System.out.println(c == 3.6f); // false
    System.out.println(Float.compare(c, 3.6f) == 0); // false
    System.out.println(c2.compareTo(BigDecimal.valueOf(3.6f)) == 0); // false
    System.out.println(c3.compareTo(BigDecimal.valueOf(3.6f)) == 0); // false
    System.out.println(c3.compareTo(BigDecimal.valueOf(3.6f).setScale(2, RoundingMode.HALF_UP)) == 0); // true
    System.out.println(c3.compareTo(BigDecimal.valueOf(3.6f).setScale(9, RoundingMode.HALF_UP)) == 0); // false
    System.out.println(c4.compareTo(BigDecimal.valueOf(3.6f).setScale(2, RoundingMode.HALF_UP)) == 0); // true
}
0
ответ дан 3 December 2019 в 13:54
поделиться

По общему правилу, числа с плавающей запятой никогда не следует сравнивать как (a == b) , а как (Math.abs (ab) < delta) , где delta - небольшое число.

Значение с плавающей запятой, имеющее фиксированное количество цифр в десятичной форме, не обязательно должно иметь фиксированное количество цифр в двоичной форме.

Дополнение для ясности:

Хотя строгое == сравнение чисел с плавающей запятой имеет очень мало практического смысла, строгое сравнение < и > , напротив, это допустимый вариант использования (пример - логический запуск, когда определенное значение превышает порог: (val> threshold) && panic (); )

19
ответ дан 3 December 2019 в 13:54
поделиться

Это слабость всех представлений с плавающей запятой, и это происходит потому, что некоторые числа, которые кажутся фиксированными в десятичной системе, на самом деле имеют бесконечное количество десятичных знаков в двоичной системе. система. Итак, то, что вы думаете, это 1.2, на самом деле что-то вроде 1.199999999997, потому что при представлении его в двоичном формате он должен отрубать десятичные дроби после определенного числа, и вы теряете некоторую точность. Затем умножение его на 3 фактически дает 3,5999999 ...

http://docs.python.org/py3k/tutorial/floatingpoint.html <- это могло бы лучше объяснить это (даже если это для python, это общая проблема представления с плавающей запятой)

2
ответ дан 3 December 2019 в 13:54
поделиться

Если вас интересуют числа с фиксированной точностью, вам следует использовать тип с фиксированной точностью, например BigDecimal , а не по своей сути приближенный (хотя и с высокой точностью) тип, например float . Существует множество похожих вопросов о переполнении стека, которые более подробно рассматриваются на многих языках.

7
ответ дан 3 December 2019 в 13:54
поделиться

Я думаю, что это не имеет ничего общего с Java, это происходит с любым числом с плавающей запятой IEEE 754. Это из-за природы представления с плавающей запятой. Любые языки, использующие формат IEEE 754, столкнутся с той же проблемой.

Как было предложено Дэвидом выше, вы должны использовать метод abs класса java.lang.Math, чтобы получить абсолютное значение (отбросьте положительный / отрицательный знак).

Вы можете прочитать это: http://en.wikipedia.org/wiki/IEEE_754_revision , а также хороший учебник по численным методам, который удовлетворит проблему.

public static void main(String[] args) {
    float a = 1.2f;
    float b = 3.0f;
    float c = a * b;
        final float PRECISION_LEVEL = 0.001f;
    if(Math.abs(c - 3.6f) < PRECISION_LEVEL) {
        System.out.println("c is 3.6");
    } else {
        System.out.println("c is not 3.6");
    }
}
5
ответ дан 3 December 2019 в 13:54
поделиться

Как и другие писали:

Сравните числа с плавающей запятой с: if (Math.abs (a - b)

Вы можете написать хороший метод для этого :

public static int compareFloats(float f1, float f2, float delta)
{
    if (Math.abs(f1 - f2) < delta)
    {
         return 0;
    } else
    {
        if (f1 < f2)
        {
            return -1;
        } else {
            return 1;
        }
    }
}

/**
 * Uses <code>0.001f</code> for delta.
 */
public static int compareFloats(float f1, float f2)
{
     return compareFloats(f1, f2, 0.001f);
}

Итак, вы можете использовать его так:

if (compareFloats(a * b, 3.6f) == 0)
{
    System.out.println("They are equal");
}
else
{
    System.out.println("They aren't equal");
}
2
ответ дан 3 December 2019 в 13:54
поделиться

Чтобы сравнить два числа с плавающей запятой, f1 и f2 с точностью до #. ### Я полагаю, вам потребуется сделайте так:

((int) (f1 * 1000 + 0.5)) == ((int) (f2 * 1000 + 0.5))

f1 * 1000 поднимает 3,14159265 ... до 3141,59265 , + 0,5 приводит к 3142,09265 а (int) отбрасывает десятичные дроби, 3142 . То есть он включает 3 десятичных знака и правильно округляет последнюю цифру.

-1
ответ дан 3 December 2019 в 13:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: