Предотвращение генерации FsCheck NaN и бесконечности

У меня есть глубоко вложенная структура данных с поплавками повсюду. Я использую FsCheck, чтобы проверить, не изменились ли данные после сериализации, а затем десериализации.

Это свойство не работает, когда число с плавающей точкой либо NaN, либо +/- бесконечность, однако такой случай меня не интересует, так как я не ожидаю, что эти значения будут встречаться в реальных данных.

Есть ли способ запретить FsCheck генерировать NaN и бесконечности?

Я попытался отбросить сгенерированные данные, содержащие указанные значения, но это делает тест невероятно медленным, настолько медленным на самом деле, что тест все еще выполняется, пока я пишу это, и я сомневаюсь, что он действительно завершится...


person phaz    schedule 30.07.2014    source источник
comment
Используйте оболочку NormalFloat github.com/fsharp/FsCheck/ blob/master/src/FsCheck/ github.com/fsharp/FsCheck/blob/master/src/FsCheck/   -  person Mauricio Scheffer    schedule 30.07.2014
comment
О, круто. Итак, как мне это сделать? :-)   -  person phaz    schedule 30.07.2014
comment
Сделайте параметры теста типа NormalFloat.   -  person Mauricio Scheffer    schedule 30.07.2014
comment
Извините, но я все еще не понимаю, что вы пытаетесь сказать. Данные, которые должны быть сгенерированы, представляют собой запись записей записей (сорта), некоторые из которых содержат числа с плавающей запятой среди прочего. Я хотел бы, чтобы все места, где должны генерироваться поплавки, не использовали NaN или бесконечности.   -  person phaz    schedule 30.07.2014
comment
Вы написали свой собственный генератор для этих данных или используете встроенный генератор на основе отражения?   -  person Kurt Schelfthout    schedule 30.07.2014
comment
У меня те же проблемы, что и у @Phazyck. В моем коде from‹int› не работает. Все функции FsCheck настолько запутаны и недокументированы, что входной барьер для использования этого фреймворка очень высок. Например. Я написал генератор для создания четных чисел. Затем я сделал с ним Arbitrary‹int›, но он не работает. Пожалуйста, сделайте его проще и лучше документируйте. Сейчас нам не нужны дополнительные функции, нам нужно больше примеров и документов.   -  person Endrju    schedule 23.08.2014


Ответы (2)


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

type Overrides() =
    static member Float() =
        Arb.Default.Float()
        |> filter (fun f -> not <| System.Double.IsNaN(f) &&
                            not <| System.Double.IsInfinity(f)) 

А потом звонит:

Arb.register<Overrides>()

Прежде чем FsCheck попытается сгенерировать типы; например в вашей тестовой настройке или перед вызовом Check.Quick.

Вы можете проверить результат метода register, чтобы увидеть, как он объединил произвольные экземпляры по умолчанию с новыми; это должно было переопределить их.

Если вы используете расширение xUnit, вы можете избежать вызова Arb.register, используя аргумент Arbitraries атрибута PropertyAttribute:

[<Property(Arbitraries=Overides)>]
person Kurt Schelfthout    schedule 30.07.2014
comment
Не могли бы вы расширить свой последний абзац примером того, как это можно сделать? - person primfaktor; 30.06.2016

Как сказал Маурисио Шеффер, вы можете использовать тип NormalFloat в тестовом параметре.

Простой пример для списка поплавков:

open FsCheck

let f (x : float list) = x |> List.map id

let propFloat (x : float list) = x = (f x)

let propNormalFloat (xn : NormalFloat list) = 
    let x = xn |> List.map NormalFloat.get
    x = f x

Check.Quick propFloat
//Falsifiable, after 18 tests (13 shrinks) (StdGen (761688149,295892075)):
//[nan]

Check.Quick propNormalFloat
//Ok, passed 100 tests.
person jindraivanek    schedule 30.07.2014
comment
Я предполагаю, что это могло бы работать в других случаях, таких как те, которые вы иллюстрируете. Проблема в том, что данные — это не просто список чисел с плавающей запятой или что-то в этом роде, что позволяет мне писать NormalFloat как часть типа, а более сложная структура, содержащая числа с плавающей запятой во всевозможных местах, а также другие типы. Что мне нужно, так это иметь FsCheck для генерации NormalFloats в любом месте, где требуется float, независимо от того, как выглядят данные, как показывает Курт Шелфтаут. :-) - person phaz; 31.07.2014