Знакът нула с поплавъци

Помислете за следния код, изпълняващ операции върху комплексни числа с float на C/C++:

float real_part = log(3.f);
float imag_part = 0.f;

float real_part2 = (imag_part)*(imag_part)-(real_part*real_part);
float imag_part2 = (imag_part)*(real_part)+(real_part*imag_part);

Резултатът ще бъде

real_part2= -1.20695 imag_part2= 0
angle= 3.14159

където angle е фазата на комплексното число и в този случай е pi.

Сега разгледайте следния код:

float real_part = log(3.f);
float imag_part = 0.f;

float real_part2 = (-imag_part)*(-imag_part)-(real_part)*(real_part);
float imag_part2 = (-imag_part)*(real_part)+(real_part)*(-imag_part);

Резултатът ще бъде

real_part2= -1.20695 imag_part2= 0
angle= -3.14159

Въображаемата част от резултата е -0, което прави фазата на резултата -pi.

Въпреки че все още се изпълнява с основния аргумент на комплексно число и със знаковото свойство на 0 с плаваща запетая, тази промяна е проблем, когато се дефинират функции на комплексни числа. Например, ако се дефинира sqrt на комплексно число чрез формулата на де Моавър, това ще промени знака на въображаемата част от резултата на грешна стойност.

Как да се справим с този ефект?


person Vitality    schedule 28.10.2013    source източник
comment
В float imag_part2 = (-imag_part)*(real_part) ... има -. В complex_number3b.y=complex_number3a.x*complex_number3a.y ... няма -. Това ли е вашето намерение?   -  person chux - Reinstate Monica    schedule 29.10.2013
comment
@chux imag_part се променя в знака и в двата случая. Когато изчислявам imag_part2, променям знака на imag_part, както забелязахте. При изчисляване на complex_number3b, промяната на знака е в рамките на complex_number3a.x, което е равно на -imag_part.   -  person Vitality    schedule 29.10.2013
comment

Опитвам се да реша дали персонализираният атрибут за оторизация, който написах, наистина е добра идея.

Сценарий
Да кажем, че имаме колекция от магазини, всеки Store има собственик. Само собственикът на магазина може да извършва CRUD операции в магазина. С ИЗКЛЮЧЕНИЕ на потребители с Claim, което основно отменя изискването за собственост и казва, че могат да извършват CRUD операции във ВСЕКИ магазин.

Странична бележка: Използвам Thinktecture и ADFS

Така че направих атрибут StoreOwnerAuthorize, чиито параметри ("Manage", "Stores") се използват за проверка дали потребителят има подходящо твърдение за „отмяна“, че не е собственик, но все пак може да премине проверката за оторизация.

Не съм сигурен как се чувствам да имам претенция като „ManageStores“ и да извикам базата данни вътре в атрибута. Това ме кара да мисля, че вървя по грешен път, въпреки че постига точно това, от което се нуждая.

API маршрути

api/v1/Store/{storeId:int:min(1)}/employees   
api/v1/Store/{storeId:int:min(1)}/inventory 

API метод

[StoreOwnerAuthorize("Manage", "Stores")]
[ResourceAuthorize("View", "Store")]
[Route("")]
//api/v1/Store/{storeId:int:min(1)}/employees 
public IHttpActionResult GetStoreEmployees(int storeId)
{
    return Ok(collectionOfStoreEmployees);
}

StoreOwnerAuthorizeAttribute

public class StoreOwnerAuthorizeAttribute : ResourceAuthorizeAttribute
{
    private readonly DbContext _context = new DbContext();

    public StoreOwnerAuthorizeAttribute(){  }
    public StoreOwnerAuthorizeAttribute(string action, params string[] resources)
        : base(action, resources) { }

    protected override bool IsAuthorized(HttpActionContext actionContext)
    {
        //If the user has the Claim that overrides the requirement that the user 
        //is the Owner of the Store, skip checking if they are the owner
        if (base.IsAuthorized(actionContext))
            return true;

        //Get route parameter to lookup Store and determine if the user is the owner
        object storeId;
        actionContext.ControllerContext.RouteData.Values.TryGetValue("storeId", out storeId);
        var isOwner = false;
        if (storeId != null)
        {
            isOwner =
                _context.Store_Get_ByStoreID(int.Parse(storeId.ToString()))
                    .Any(x => x.OwnerId == theUser.Id());
        }
        return isOwner;
    }
}
  -  person Pascal Cuoq    schedule 29.10.2013
comment
@chux, извинявам се. Ти беше права. Редактирах публикацията си.   -  person Vitality    schedule 29.10.2013


Отговори (1)


РЕДАКТИРАНЕ: сега, когато изглежда, че въпросът има смисъл, изглежда като въпроса, на който Кахан отговаря, когато пише, в статията си Разрязване на клони за сложни елементарни функции:

Като цяло аритметиката в смесен режим, комбинираща реални и комплексни променливи, трябва да се извършва директно, а не чрез първо принудително превръщане на реалните в комплексни, за да не се окаже, че знакът нула е неинформативен; същото важи и за комбинации от чисти имагинерни величини с комплексни променливи. И правенето на аритметика директно по този начин спестява време за изпълнение, което иначе би било пропиляно при манипулиране на нули.

С други думи, дори основният дизайнер на стандарта IEEE 754 не знае как да направи знака нула да има смисъл при изчисляване на комплексни числа, някои от които са повишени от реални числа.


Отговор на първоначалния въпрос:

Не виждам нищо лошо в изчисленията, които показваш.

float imag_part = 0.f;

float imag_part2 = (-imag_part)*(real_part)+(real_part*imag_part);

Това задава imag_part2 на -0. + 0., което е +0. в кръга към най-близкото.

complex_number3b.y=complex_number3a.x*complex_number3a.y+complex_number3a.y*complex_number3a.x;

Това се оценява на -0. + -0., което само по себе си се оценява на -0..

Вашите две изчисления не са еквивалентни, нормално е те да не дават същия резултат. И двата резултата са в съответствие с правилата на IEEE 754 за знака нула.

person Pascal Cuoq    schedule 28.10.2013
comment
Благодаря ви много за бързия отговор. Не твърдя, че нещо не е наред. Донякъде съм изненадан, тъй като изчисленията изглеждат напълно еквивалентни. Те очевидно трябва да изпълняват точно същите операции, както може да се заключи от буквалното заместване на -imag_part и real_part на мястото на complex_number3a.x и complex_number3a.y, съответно. Но може би това е въпрос на невидимото поведение на компилатора. Истинският ми въпрос в долната част на публикацията е как да се справя с този ефект? Има ли последователен начин за работа с комплексни числа? - person Vitality; 29.10.2013
comment
@JackOLantern Вие сте написали …+(real_part*imag_part). Заместването на complex_number3a.x с -imag_part в …+complex_number3a.y*complex_number3a.x не води до …+(real_part*imag_part). Ако направите замяната правилно, ще получите същия резултат. Начинът да се справите с ефекта, който описвате, е да направите правилното заместване. - person Pascal Cuoq; 29.10.2013
comment
съжалявам Ти си прав. Направих малко объркване. Моля, вижте моята редактирана публикация. Проблемът ми е, че в зависимост от знака на 0, мога да имам различни резултати, когато прилагам формулата на de Moivre. Има ли някакъв стандартен трик за справяне с това? - person Vitality; 29.10.2013
comment
Благодаря ви много за отговора. Изясни ми откъде идва проблемът, както и предложи възможни насоки за справяне с него. - person Vitality; 30.10.2013