Добавлен
Мне нужно преобразовать real в integer так, чтобы каждый real имел свой integer (как у функции GetHandleId( ), только вместо handle должен быть real). Нативная функция R2I( ) может вернуть одно и то же значение для разных real'ов ( R2I( 0.01 ) == R2I( 0.02 ) ).

Попробовал умножать real на 10 000 000, так, например, GetRealId( 0.03125 ) == 312500, но так можно упереться в потолок 2147483647
function GetRealId takes real whichReal returns integer
	return ( whichReal * 10000000 )
endfunction

В мемхаке нашел следующую функцию, но хотелось бы, чтобы функция работала без return bug'a
раскрыть
//# +nosemanticerror
    function realToIndex takes real r returns integer
        loop
            return r
        endloop
        return 0
    endfunction

    function cleanInt takes integer i returns integer
        return i
    endfunction

    function mR2I takes real r returns integer
        return cleanInt( realToIndex( r ) )
    endfunction
Можно сократить до (вроде работает):
//# +nosemanticerror
    function R2IEx takes real r returns integer
        loop
            return r
        endloop
        return 0
    endfunction

Принятый ответ

Сделал следующим образом:
раскрыть
	function interface callback takes integer this returns nothing defaults nothing


    struct linkedList

        private static timer    period      = null
        private        real     curTimeout
        private        real     timeout
        private        thistype prev
        private        thistype next
        private        callback handlerFunc


		static constant method operator listPeriod takes nothing returns real
            return 0.01
        endmethod


        method destroy takes nothing returns nothing
            set this.prev.next = this.next
            set this.next.prev = this.prev

            if (thistype(0).next == thistype(0)) then
                call PauseTimer(this.period)
            endif

            call thistype.deallocate(this)
        endmethod


        private static method iterate takes nothing returns nothing
            local thistype this = thistype(0).next

            loop
                exitwhen (this == thistype(0))

                set this.curTimeout = this.curTimeout + thistype.listPeriod

                if (this.curTimeout >= this.timeout) then
                    set this.curTimeout = 0.0
                    call this.handlerFunc.evaluate(integer(this))
                endif

                set this = this.next
            endloop
        endmethod


        static method create takes real timeout, callback handlerFunc returns thistype
            local thistype this = thistype.allocate()

            set this.next        = thistype(0)
            set this.prev        = thistype(0).prev
            set this.next.prev   = this
            set this.prev.next   = this
            set this.timeout     = timeout
            set this.curTimeout  = 0.0
            set this.handlerFunc = handlerFunc

            if (thistype.period == null) then
                set thistype.period = CreateTimerEx()
            endif

            if (this.prev == thistype(0)) then
                call TimerStart(thistype.period, thistype.listPeriod, true, function thistype.iterate)
            endif

            return this
        endmethod


    endstruct
Будет ли это создавать большую нагрузку на игру из-за низкого периода таймера, несмотря на то, что таймер хоть и работает с низкой частотой, он ничего толком то и не делает, кроме арифметических вычислений?
`
ОЖИДАНИЕ РЕКЛАМЫ...
3
16
6 лет назад
Отредактирован Naadir
3
каждый real имел свой integer
Иными словами, ты хочешь, чтобы множество R было равномощно множеству N? Это невозможно, т.к. N счётно, а R несчётно.

Тебе придётся довольствоваться твоим нынешним решением, где из R в N ты строишь сюръективное отображение.
1
15
6 лет назад
1
>Мне нужно преобразовать real в integer так, чтобы каждый real имел свой integer
То есть ты хочешь множеству поставить в соответствие подмножество себя же самого?
Загруженные файлы
1
16
6 лет назад
1
Или биекция, но с ограничением (-maxint;maxint).
0
21
6 лет назад
0
Если честно, то даже не понял, что это за слова вы мне написали.(

Думаю, будет лучше, если я объясню для чего мне это нужно.
Мне нужно прикрепить к real'y handle, но все способы, что мне известны, реализованы через integer (структуры, массивы переменных, хеш-таблицы).

Сперва думал, что смогу сделать через параллельные массивы:
reals[ index ] = 0.056465
handle[ index ] = whichTimer
но как то не получилось, да и к циклам приходится постоянно прибегать. А если сделать через GetRealId( ), то получилось бы всё очень просто:
handle[ GetRealId( 0.056465 ) ] = whichTimer
всё очень просто, таймер хранится в ячейке 0.056465.
1
16
6 лет назад
1
ScopteRectuS, упрощённо: твоя задача невыполнима. Если ты хочешь сопоставлять натуральные и действительные числа, тебе нужно смириться с тем, что R2I(0.01) = R2I(0.02). Либо при умножении на 100 R2I(0.02001) = R2I(0.02002).
0
30
6 лет назад
0
Почему здесь вообще фигурирует real?
0
21
6 лет назад
0
Naadir, а как работает функция из мемхака? она же как-то выдаёт разные значения.
Clamp, потому что мне нужно прикрепить объект к real'y
2
17
6 лет назад
Отредактирован GetLocalPlayer
2
Зачем оно тебе надо, не мое дело. Но если надо, можешь преобразовать действительное число в строку и получить хэш этой строки через StringHash.
3
30
6 лет назад
3
потому что мне нужно прикрепить объект к real'y
Почему?

У тебя где-то есть очевидная ошибка в дизайне логики, из-за которой возникла текущая проблема.
0
21
6 лет назад
Отредактирован scopterectus
0
GetLocalPlayer, проверил, R2S( ) округляет. R2S( 0.03125 ) > "0.031"
Clamp, вот небольшая библиотека, которая позволяет использовать один периодический таймер на всю карту.
раскрыть

    function interface callback takes integer this returns nothing defaults nothing


    struct linkedList


        static constant method getListPeriod takes nothing returns real
            return ( 0.03125 )
        endmethod


        private  static  constant  timer     period       =  CreateTimer( )
        private                    thistype  prev
        private                    thistype  next
        private                    callback  handlerFunc


        method destroyList takes nothing returns nothing
            set  this.prev.next  =  this.next
            set  this.next.prev  =  this.prev

            if ( thistype( 0 ).next == thistype( 0 ) ) then
                call PauseTimer( thistype.period )
            endif

            call thistype.deallocate( this )
        endmethod


        private static method iterateList takes nothing returns nothing
            local  thistype  this  =  thistype( 0 ).next

            loop
                exitwhen ( this == thistype( 0 ) )

                call this.handlerFunc.evaluate( integer( this ) )

                set  this  =  this.next
            endloop
        endmethod


        static method createList takes callback handlerFunc returns thistype
            local  thistype  this  =  thistype.allocate( )

            set  this.next         =  thistype( 0 )
            set  this.prev         =  thistype( 0 ).prev
            set  this.next.prev    =  this
            set  this.prev.next    =  this
            set  this.handlerFunc  =  handlerFunc

            if ( this.prev == 0 ) then
                call TimerStart( thistype.period, thistype.getListPeriod( ), true, function thistype.iterateList )
            endif

            return this
        endmethod


    endstruct
Как видно из кода, метод createList( ) берет лишь функцию, которую будет запускать по истечении таймера, а период таймера там статичный. Я же хочу допилить свой код, чтобы этот метод еще и брал период таймера, и, если это новый период таймера, то создаётся новый таймер, если же нет, то действие добавляется к уже существующему таймеру с таким же периодом.
Получилось бы примерно следующее:
static method createList takes real timeout, callback handlerFunc returns thistype
	...
	if timers[ timeout ] == null then
		set timers[ timeout ] = CreateTimer( )
	endif
	...
endmethod
0
30
6 лет назад
0
ScopteRectuS, таким образом ты пытаешься экономить таймеры, я правильно понял?
0
21
6 лет назад
0
Clamp, и экономить, и просто сделать. Да и код становится более читабелен, написал одну функцию и всё, не нужно ничего крепить, создавать, запускать...
3
30
6 лет назад
Отредактирован Clamp
3
экономить
Таймер - самый лёгкий объект в системе, ты по факту ничего не экономишь, избавляясь от "лишних". Кроме того, лучше не смешивать контексты.

Вся оптимизация, что тебе нужна - это упаковка создания нового таймера в один вызов.
0
21
6 лет назад
Отредактирован scopterectus
0
Clamp, всё равно, даже если это будет более ресурсозатратным, чем простое создание и удаление таймеров, хотелось бы довести свое дело до конца.
Я бы сказал, что мною движет желание это сделать больше, чем оптимизация кода.
0
30
6 лет назад
0
Доводить до совершенство алгоритмы, неверные в самой своей основе - тупиковый маршрут, но как хочешь.
Вариант со StringHash(R2S(r)) здесь будет наиболее уместным, однако помни, что строки никуда из памяти не деваются, и остаются висеть в оперативе.
0
18
6 лет назад
0
ScopteRectuS:
GetLocalPlayer, проверил, R2S( ) округляет. R2S( 0.03125 ) > "0.031"
Попробуй R2SW
0
21
6 лет назад
0
Clamp, я же написал:
GetLocalPlayer, проверил, R2S( ) округляет. R2S( 0.03125 ) > "0.031"
call BJDebugMsg( I2S( StringHash( R2S( 0.03125 ) ) ) ) == -1331723389
call BJDebugMsg( I2S( StringHash( R2S( 0.03126 ) ) ) ) == -1331723389
1
28
6 лет назад
Отредактирован PT153
1
The return-loop hack в помощь.
В математике R не ограничено, но наш мир ограничен, потому число действительных чисел ограничено в программировании. Каждому целому числу сопоставлено число с плавающей точкой.
Не используй R2S, это R2SW с точностью 3. Лучше используй R2SW с точностью -1.
function R2SX takes real r returns string
    return R2SW(r, 0, -1)
endfunction
1
17
6 лет назад
1
GetLocalPlayer, проверил, R2S( ) округляет. R2S( 0.03125 ) > "0.031"
Как заметил UrsaBoss, есть функция R2SW, чья максимальная точность - 9 знаков, но даже в этом случае будет иметь место округление.
В целом Clamp, говорит верно, такие потребности не должны возникать в логике программы, поскольку типы с плавающей запятой ненадежны, они с потерями.
Если нужно совсем прям совсем, можно использовать vJass/ZINC/Wurst и объявить структуру (в случае Wurst - класс) который будет содержать в поле данные типа real. Что-то вроде
Код
struct Float
	private real value
	
	static method create takes real newValue returns Float
	    local Float this = Float.allocate()
	    set value = newValue
	    return this
	endmethod
	
	method getValue takes nothing returns real
	    return value
	endmethod
	
	method setValue takes real newValue returns nothing
	    set value = newValue
	endmethod
endstruct
Тогда каждый экземпляр структуры будет обладать уникальным целочисленным значением в диапазоне от 1 до 8190 (или больше, если в патче 1.28+), эдакая ссылочная обертка для примитивного типа.
0
26
6 лет назад
0
ScopteRectuS, так а чем конкретно не устраивает вариант массификации ряда реальных чисел?
0
28
6 лет назад
0
Тогда каждый экземпляр структуры будет обладать уникальным целочисленным значением в диапазоне от 1 до 8190 (или больше, если в патче 1.28+), эдакая ссылочная обертка для примитивного типа.
Вот кстати да, можно же сделать структуру! Но the return-loop hack лучше, потому что ограничений нет, в отличие от структур.
1
16
6 лет назад
1
варкрафт супер ненадежен в реалках, зачем эти костыли? Нет места под инт - создай еще один массив или хт под нужды. Задача не может быть выполнена ПО ВСЕМ возможным случаям. Для ограничений - пожалуйста, R2SW и прочие извращения. Но такой же свободы, как с обычными интами, ты не получишь по определению
0
32
6 лет назад
0
я не очень прошарил тему, и вообще мало чего понимаю в том что вы тут понаписали - увы не кодер от слова совсем. Но.
Если бы мне нужно было бы хранить что-то в массиве данных с привязкой к числу 0.5683, то я бы конвертнул это число в строку, через конкат нашел бы и убрал бы "0." а оставшееся значение конвертнул бы в int и под этим значением записал бы ячейку массива.
0
30
6 лет назад
0
Fakov, А если число пятизначное?
0
32
6 лет назад
0
Clamp:
Fakov, А если число пятизначное?
какая разница если у него впереди есть ноль с точкой. если не требуется обратного конверта - то все ок. Интежер из R2S(0.05678) будет '5678'
Уверен, обратно конвертнуть интежер в исходный real тоже можно
Чтобы оставить комментарий, пожалуйста, войдите на сайт.