Couple questions about efficiency

Post » Tue Nov 20, 2012 3:11 pm

Is it better to store an array of booleans than integers? I read that all numbers are stored as floats and I actually encountered a problem with this when I tried to use an integer to store 30 flags. My searches haven't yielded any info about how booleans are stored.

Also, can booleans be cast to integers? I have 6 boolean properties as conditional in a quest script so that I could toggle buttons in a menu. This isn't working. The code below shows it as it is now but I'll be changing those conditionals to ints. This means that I need to change some code below and if bools cannot be cast to ints then I need more lines. In the script below, the button vars are bShowButton*

Oh yeah, almost forgot my 3rd question. How many times does a script need to call another script for it to be worth importing said script? This script has one line that calls Game.Function 3 times and this in OnUpdate which runs every 3 seconds until character creation is finished. Is it possible to only import certain functions from a script? Could I copy the native functions from the game script and paste them into this script?

I'm not the best at commenting my code :-p
Spoiler
Scriptname _CCMenuScript extends Quest  Conditional{Classic Classes and Birthsigns menu script rewritten by selyb}Actor Property aPlayer AutoSpell Property _CCAcrobatAbilityMagSho AutoSpell Property BoundSword AutoSpell Property HealingHands AutoSpell Property Courage Automessage property _CCTopMenu automessage property _CCAdventurerMenu automessage property _CCSpecializationMenu automessage property _CCCombatSpecializationMenu automessage property _CCStealthSpecializationMenu automessage property _CCMagicSpecializationMenu automessage property _BSTopMenu Automessage property _BSTravelerMenu Automessage property _BSBirthsignMenu Automessage property _BSBirthsignChoiceMenu Automessage property _CCCurrentCharacter Automessage property _CCCurrentBirthsignMenu AutoGlobalVariable property SpeechEasy AutoGlobalVariable property SpeechAverage AutoGlobalVariable property SpeechHard AutoGlobalVariable property SpeechVeryHard Automessage property _CCCustomTopMenu automessage property _CCCustomSpecialist automessage property _CCCustomClassConfirm automessage property _CCCustomSecondarySkills autobool Property bShowButton0 Auto Conditionalbool Property bShowButton1 Auto Conditionalbool Property bShowButton2 Auto Conditionalbool Property bShowButton3 Auto Conditionalbool Property bShowButton4 Auto Conditionalbool Property bShowButton5 Auto ConditionalMessage[] Property aMenus  Auto  Message[] Property aSignMessages  Auto  SPELL[] Property aSignSpells1  AutoSPELL[] Property aSignSpells2  Auto  Message[] Property aSpecializationMenus  Auto	;All 21 menusInt[] Property aClassOptionFlags Auto  ;Elements 0-20 to store option flags for each of the 21 classesSPELL[] Property aClassAbilities Auto	;Store the base class abilities, these three arrays are parallelMessage[] Property aCustomSkillMenus  Auto	;6 custom character skill menusSPELL[] Property aClassSkill1  Auto	  ;Store secondary Skills/Spells hereSPELL[] Property aClassSkill2  Auto	  ;Store tertiary Skills/Spells hereString[] Property aSkills  Auto  ;Store the actor value names here for use with SetAVBool[] Property aClassChoices  Auto  ;Elements 0-24 for buildclass optionsEvent OnInit()  RegisterForSingleUpdate(1)EndEventEvent OnUpdate()  ; selyb - I robbed this line from Character Creation Overhaul by Syclonix and modified it a little  If Game.IsFightingControlsEnabled() && Game.IsActivateControlsEnabled() && Game.IsJournalControlsEnabled() && !Utility.IsInMenuMode()	MainMenu()  Else	RegisterForSingleUpdate(3)  EndIfEndEventFunction MainMenu()  int iPage = 1  int iChoice  bool bContinue = True  While bContinue	If iPage == 1  ;TopMenu	  iChoice = _CCTopMenu.Show()	  ;  0 = AdventurerMenu, 1 = SpecializationMenu, 2 = CustomClassMenu	  iPage = iChoice + 2	ElseIf iPage == 2  ;AdventurerMenu	  If _CCAdventurerMenu.Show()	;Back		iPage = 1	  Else  ;BSTopMenu		iPage = 6	  EndIf	ElseIf iPage == 3  ;SpecializationMenu	  iChoice = _CCSpecializationMenu.Show()	  If iChoice == 3  ;Back		iPage =1	  Else  ;0 is Combat, 1 is Stealth, 2 is Magic		iPage = 9 + iChoice	  EndIf	ElseIf iPage == 4  ;CustomClassMenu	  If CustomClassLoop()		iPage = 6	  Else  ;Cancelled		iPage = 1	  EndIf	ElseIf iPage == 5  ;CurrentBirthsignMenu	  If _CCCurrentBirthsignMenu.Show()  ;Return to game		bContinue = False	  Else  ;		iPage = 6	  EndIf	ElseIf iPage == 6  ;BSTopMenu	  If _BSTopMenu.Show()  ;BirthsignChoice		iPage = 7	  Else  ;TravelerMenu		iPage = 8	  EndIf	ElseIf iPage == 7  ;BirthsignChoice	  iChoice = _BSBirthsignChoiceMenu.Show()	  If iChoice == 2	;Back		iPage = 6	  Else		bContinue = !BSHelper(iChoice * 13)	  EndIf	ElseIf iPage == 8  ;TravelerMenu	  If _BSTravelerMenu.Show()	;Back		iPage = 6	  Else	;Done		bContinue = False	  EndIf	Else  ;If iPage > 8	  If iPage == 9		iChoice = _CCCombatSpecializationMenu.Show()	  ElseIf iPage == 10		iChoice = _CCStealthSpecializationMenu.Show()	  Else  ;If iPage == 11		iChoice = _CCMagicSpecializationMenu.Show()	  EndIf	  If iChoice == 7  ;Back		iPage = 3	  Else		iChoice *= iPage - 9		If aSpecializationMenus[iChoice].Show()		  aPlayer.AddSpell(aClassAbilities[iChoice])		  If aClassAbilities[iChoice]			aPlayer.AddSpell(aClassAbilities[iChoice])		  EndIf		  If iChoice == 3  ;			aPlayer.AddSpell(Courage)		  ElseIf iChoice == 7  ;			aPlayer.AddSpell(_CCAcrobatAbilityMagSho)		  ElseIf iChoice == 8  ;Agent			SpeechEasy.SetValue(70)			SpeechAverage.SetValue(70)			SpeechHard.SetValue(70)			SpeechVeryHard.SetValue(70)		  ElseIf iChoice == 15  ;			aPlayer.AddSpell(HealingHands)		  ElseIf iChoice == 18  ;			aPlayer.AddSpell(BoundSword)		  EndIf		  SetOptions(aClassOptionFlags[iChoice])		  BuildClass()		  iPage = 6		EndIf	  EndIf	EndIf  EndWhileEndFunctionFunction SetOptions(int iFlags)  ;This function takes an integer and converts it to 24 booleans			  ;Without this, we would have to store a boolean array for each of the 21 classes  int iCurFlag = 8388608  ;Start with 2^23  int x = 23  ;Current iteration  ;Start at option 23  While iFlags  ;Once we have found all flags and subtracted them, this will be 0 and we don't need to loop anymore	If iFlags / iCurFlag > 1  ;If the current flag exists then this division will be > 1 otherwise a fraction < 1	  iFlags -= iCurFlag	;Subtract the current flag from our flags value so that the next loop will work correctly :)	  aClassChoices[x] = True	;Turn the option on	EndIf	x -= 1	iCurFlag /= 2	;In binary this means /10 in essence bringing us to the next lower possible flag  EndWhileEndFunctionbool Function CustomClassLoop()  int iPage = 1  int iChoice  int iNumSkills = 7  bool bRet = True  int iSpecBonus = 2  While iPage	If iPage == 1  ;CustomTopMenu	  bShowButton5 = !iNumSkills	  iChoice = _CCCustomTopMenu.Show(iNumSkills)	  If iChoice == 0  ;SpecBonusMenu		iPage = 2	  ElseIf iChoice == 4  ;Secondary Skills		iPage = 3	  ElseIf iChoice == 5  ;Next		iPage = 0	  ElseIf iChoice == 6  ;Cancel		If _CCCustomClassConfirm.Show()		  bRet = False		  iPage = 0		EndIf	  Else		iPage = ((iChoice - 1) * 2) + 4	  EndIf	ElseIf iPage == 2  ;SpecBonusMenu	  bShowButton0 = iSpecBonus != 1	  bShowButton1 = iSpecBonus == 1	  bShowButton2 = iSpecBonus != 2	  bShowButton3 = iSpecBonus == 2	  bShowButton4 = iSpecBonus != 3	  bShowButton5 = iSpecBonus == 3	  iChoice = _CCCustomSpecialist.Show()	  If iChoice == 0		iSpecBonus = 1	  ElseIf iChoice == 2		iSpecBonus = 2	  ElseIf iChoice == 4		iSpecBonus = 3	  Else		iPage = 1	  EndIf	ElseIf iPage == 3  ;Secondary Skills	  iChoice = _CCCustomSecondarySkills.Show()	  If iChoice == 5  ;Back		iPage = 1	  Else		aClassChoices[18] = iChoice		aClassChoices[19] = iChoice != 1		aClassChoices[20] = iChoice != 2		aClassChoices[21] = iChoice != 3		aClassChoices[22] = iChoice != 4	  EndIf	ElseIf iPage < 10  ;Skill Menus	  iPage -= 4	;It makes fewer calculations to subtract 4 here and add it back later	  ;Buttons 0, 2, and 4 are the add skill buttons. 1, 3, and 5 are the remove buttons corresponding to 0, 2, and 4	  ;For 0, 2, and 4 we check to make sure we have available skills and then check to see if the skill has already been chosen	  bShowButton0 = iNumSkills  && !aClassChoices[iPage * 3]	  bShowButton1 = aClassChoices[iPage * 3]	  bShowButton2 = iNumSkills && !aClassChoices[(iPage * 3) + 1]	  bShowButton3 = aClassChoices[(iPage * 3) + 1]	  bShowButton4 = iNumSkills && !aClassChoices[(iPage * 3) + 2]	  bShowButton5 = aClassChoices[(iPage * 3) + 2]	  iChoice = aCustomSkillMenus[iPage].Show(iNumSkills)	  If iChoice == 8  ;Back		iPage = 1	  ElseIf iChoice == 7  ;Next		iPage += 1		If iPage == 6		  iPage = 0		EndIf	  ElseIf iChoice == 6  ;Prev		iPage -= 1		If iPage == -1		  iPage = 5		EndIf	  Else  ;Toggle		;If iChoice is 1, 3, or 5, change it to 0, 2, or 4		iChoice -= (iChoice % 2)		iChoice *= iPage		If aClassChoices[iChoice]		  aClassChoices[iChoice] = False		  iNumSkills += 1		Else		  aClassChoices[iChoice] = True		  iNumSkills -= 1		EndIf	  EndIf	  iPage += 4	EndIf  EndWhile  If bRet	BuildClass()  EndIfEndFunctionbool Function BSHelper(int iMenuOffset)	;Use an offset so we can put both eras into the same arrays and reuse the same loops  ; This clever function saved us around 140 lines of redundant code  ^_^  bool bContinue = True  bool bMainMenu = True  ;Otherwise submenu  int iSign	;This will be used to determine which spells to add  int iChoice  int iMenu = 3  ;This is used to determine which menu to show  While bContinue	iChoice = aMenus[iMenu].Show()	If bMainMenu	  If iChoice == 4	;Back		iSign = 0		bContinue = False	  ElseIf iChoice == 3  ;SerpentMenu		iSign = 13 + iMenuOffset	  Else		iMenu = iChoice		bMainMenu = False	  EndIf	Else  ;SubMenu	  If iChoice == 4	;Back		bMainMenu = True		iMenu = 3	  Else		iSign = (iMenu * 4) + iChoice + 1 + iMenuOffset	  EndIf	EndIf	If iSign	  If aSignMessages[iSign].Show()	;Back		iSign = 0	  Else	;Confirmed		bContinue = False	  EndIf	EndIf  EndWhile  If iSign	; CleanUpSigns	; selyb - Since the doom abilities are only passed in an array, we need this loop	If iMenuOffset  ;This will be non-zero if chose 4E sign menu	  iChoice = 14	;I just reused an existing variable that isn't needed anymore in this function	  While iChoice < 27  ;The doom abilities reside in elements 14 - 26		aPlayer.RemoveSpell(aSignSpells1[iChoice])		iChoice += 1	  EndWhile	EndIf	aPlayer.AddSpell(aSignSpells1[iSign])	If aSignSpells2[iSign]	  aPlayer.AddSpell(aSignSpells2[iSign])	EndIf	Return True	;Global exit  Else	Return False	;Back to BSTopMenu  EndIfEndFunctionFunction BuildClass(int iSpecBonus = 0)  ;pass Spec Bonus so we don't have to make a global for it  int x	;Used for loop iteration count  int iBonus  ;/ I use an array of bools along with 5 conditional bools to show/hide menu buttons	This shows the order that this script expects skills e.g. in the array of bools	 0) OneHanded	1	 1) TwoHanded	  2	 2) Archery		4	 3) Block		  8	 4) Smithing		16	 5) HeavyArmor	32	 6) LightArmor	64	 7) Pickpocket	  128	 8) Lockpicking	  256	 9) Sneak		  512	10) Alchemy		1024	11) Speech		2048	12) Enchanting	  4096	13) Alteration	  8192	14) Conjuration	  16384	15) Destruction		32768	16) Illusion	  65536	17) Restoration	  131072	18) CCAcrobaticsAbility	262144	19) CCAthleticsAbility	  524288	20) Pilgrim			  1048576	21) CCUnarmoredAbility	2097152	22) CCMysticismAbility	  4194304	23) CCUnarmedBonus	  8388608  /;  ;Set SpecBonus  If iSpecBonus	aPlayer.SetAV(aSkills[iSpecBonus + 17], aPlayer.GetAV(aSkills[iSpecBonus + 17]) + 20)  EndIf  ;Set Skills + Custom Perks  While x < 24	If x < 18	  iBonus = -10	  If aClassChoices[x]		iBonus = 10	  EndIf	  aPlayer.SetAV(aSkills[x], aPlayer.GetAV(aSkills[x] + iBonus))	EndIf	If x > 12	  aPlayer.AddSpell(aClassSkill1[x - 13])	  If x < 21		aPlayer.AddSpell(aClassSkill2[x - 13])	  EndIf	EndIf  EndWhileEndFunction
User avatar
Steve Fallon
 
Posts: 3503
Joined: Thu Aug 23, 2007 12:29 am

Post » Tue Nov 20, 2012 6:19 am

Hello.

Is it better to store an array of booleans than integers?
If you mean which is faster to store bitfields, no one can answer that, this is really something you need to test. In any other language I would say "use integer" but papyrus is not any other language. I guess the arrays are faster here but it's just a guess.
Now, do you have a performance problem or are you just paranoid? If you do not have any problem, go for the boolean arrays route anyway, it's cleaner and easier (since we do not have bitwise operators), and changing your code will be faster. If you see a problem later, you will just have to fix it.
Especially, if your code is only rarely ran (and it looks like it is since it's just in a menu), do not even bother thinking about optimization, focus on code quality.

I read that all numbers are stored as floats and I actually encountered a problem with this when I tried to use an integer to store 30 flags.
I never heard about that but if it's true, IEEE 32 bits floats have 23 significant bits (sign bit excluded). This means that you can use them as 23 bits integers without any problem since all those numbers have a finite representation. At worst you may observe a different behavior here and there (overflow behavior especially).

However you can also store numbers such as (23 bits)*2^n where n is up to 8 bits. But you cannot store more than 23 flags at once or rounding errors will occur (2^23 + 1 = 2^23 or 2^23 + 2).

A final word. Most programmers mistake rounding errors (very rarely encountered) with representation errors (periodically encountered).
* Rounding errors occur when you need too many digits to represent a number, for example 2^40 + 1. Even if you can represent each operand, you won't have enough digits to represent this sum so it will be rounded or truncated.
* Representation errors occur when specifying decimal numbers that have no finite representation in binary. For example: 1/3 has an infinite number of digits in base 10 but a finite one in base 3. 1/10 has a finite number of digits in base 10 but an infinite one in base 2. Etcetera. Note that any integer up to 2^23 (exclusive) can be safely represented without any representation error through 32 bits IEEE floats.

Oh yeah, almost forgot my 3rd question. How many times does a script need to call another script for it to be worth importing said script?
"Import" is just syntactic sugar and has no effect on performances. Your functions are not imported.
But again, beware of premature optimization ! Why do you think you need those kind of optimizations?

Could I copy the native functions from the game script and paste them into this script?
No.
But what would be the point? Calling a native function (unless categorized as non-delayed on the wiki) pauses your script for one frame and often releases the lock, so having it declared on your script would not make any difference.


Finally, let me insist: beware of premature optimization. This is not a good way to achieve real optimization but it's a sure way to mess up your code.
User avatar
remi lasisi
 
Posts: 3307
Joined: Sun Jul 02, 2006 2:26 pm

Post » Tue Nov 20, 2012 4:31 pm

since we do not have bitwise operators

SKSE to the rescue! (as always)

Spoiler
int Function LeftShift(int value, int shiftBy) global native
int Function RightShift(int value, int shiftBy) global native
int Function LogicalAnd(int arg1, int arg2) global native
int Function LogicalOr(int arg1, int arg2) global native
int Function LogicalXor(int arg1, int arg2) global native
int Function LogicalNot(int arg1) global native
User avatar
REVLUTIN
 
Posts: 3498
Joined: Tue Dec 26, 2006 8:44 pm

Post » Tue Nov 20, 2012 3:48 am

Int arrays are consistently, yet only marginally faster than boolean arrays when walking through one of each with 128 elements. Both are substantially faster, however, than walking through a FormList of equivalent length. Suffice it to say, a human won't notice the slight difference in the Int/Bool Arrays' speeds.

Bools can be casted to Ints and visa versa. The second won't compile w/o 'As Int' affixed while the first will auto-cast from Int to Bool.
bSomeBool = iSomeInt ;  != 0 As Bool
iSomeInt = bSomeBool As Int

OnUpdate could be expedited by pulling the '&&' as it'll otherwise check each condition in that line even if the first condition is false.
Spoiler
Event OnUpdate()	If Utility.IsInMenuMode()	ElseIf Game.IsFightingControlsEnabled()		If Game.IsActivateControlsEnabled()			If Game.IsJournalControlsEnabled()				MainMenu() ; Showtime!				Return ; No re-registration			EndIf		EndIf	EndIf	RegisterForSingleUpdate(3.0)EndEvent
User avatar
Your Mum
 
Posts: 3434
Joined: Sun Jun 25, 2006 6:23 pm

Post » Tue Nov 20, 2012 9:38 am

@Perdev: Thank you that is very informative. I can tell you with absolute certainty that you will encounter rounding errors if you try to store a large number in a GlobalVariable long. I thought I could store 2^24 accurately but I must have been wrong about that. I thought that there were 24 significant bits, 7 exponent bits and 1 sign bit. I only read up on this the other day since I never needed to know before I tried to store bit flags in papyrus :-p

About needing optimization? I don't necessarily need it. It's the kind of person I am, not just in scripting but in daily life as well. Sometimes it's a curse and other times a blessing.

SKSE to the rescue! (as always)
I have considered this and it doesn't make sense to require SKSE for one simple function when I have a great workaround.
User avatar
Fiori Pra
 
Posts: 3446
Joined: Thu Mar 15, 2007 12:30 pm

Post » Tue Nov 20, 2012 6:37 pm

Int arrays are consistently, yet only marginally faster than boolean arrays when walking through one of each with 128 elements. Both are substantially faster, however, than walking through a FormList of equivalent length. Suffice it to say, a human won't notice the slight difference in the Int/Bool Arrays' speeds. Bools can be casted to Ints and visa versa. The second won't compile w/o 'As Int' affixed while the first will auto-cast from Int to Bool.
bSomeBool = iSomeInt ; != 0 As Bool
iSomeInt = bSomeBool As Int
OnUpdate could be expedited by pulling the '&&' as it'll otherwise check each condition in that line even if the first condition is false.
Spoiler
Event OnUpdate()	If Utility.IsInMenuMode()	ElseIf Game.IsFightingControlsEnabled()		If Game.IsActivateControlsEnabled()			If Game.IsJournalControlsEnabled()				MainMenu() ; Showtime!				Return			EndIf		EndIf	EndIf	RegisterForSingleUpdate(3.0)EndEvent
Thx for this. I would have done it that way because I understood the same thing about all expressions being evaluated except that the Operator_Reference page at creationkit.com says it will short-circuit if the left evaluates as false. Is the wiki incorrect or is it different with my code since I have so many strung together?
User avatar
Teghan Harris
 
Posts: 3370
Joined: Mon Mar 05, 2007 1:31 pm

Post » Tue Nov 20, 2012 8:28 am

@Perdev: Thank you that is very informative.
You're welcome. :smile:

I can tell you with absolute certainty that you will encounter rounding errors if you try to store a large number in a GlobalVariable long.
Interssting, thank you. It may be possible that Bethesda first converts to an int32. Unfortunately they had to deal with many different CPU architectures (PC, PS3, future consoles since the engines was built for the future) and it may explain some of the oddities with Papyrus.

I thought I could store 2^24 accurately but I must have been wrong about that. I thought that there were 24 significant bits, 7 exponent bits and 1 sign bit.
I just checked on http://en.wikipedia.org/wiki/IEEE_floating_point#Basic_formats and this is really 23 + 1 + 8 for the standard single type. The http://www.creationkit.com/Literals_Reference#Float_Literals that it uses this very format (omw to enrich this page).
Now, beware: with 23 bits you can actually only store numbers up to (2^23 - 1), 2^23 is an overflow.
User avatar
Carlitos Avila
 
Posts: 3438
Joined: Fri Sep 21, 2007 3:05 pm

Post » Tue Nov 20, 2012 4:27 am

Thx for this. I would have done it that way because I understood the same thing about all expressions being evaluated except that the Operator_Reference page at creationkit.com says it will short-circuit if the left evaluates as false. Is the wiki incorrect or is it different with my code since I have so many strung together?
You're right, from all I can tell. Awesome! If the first condition in a string of '&&' is false, it resolves just as quickly as if the same, first condition is the only condition. ObScript/Legacy would check all of 'em, so that's a definite improvement.

I guess the only thing that does matter is that the least likely condition to be true is the first in line. Cool!
User avatar
Marlo Stanfield
 
Posts: 3432
Joined: Wed May 16, 2007 11:00 pm

Post » Tue Nov 20, 2012 10:23 am

@Perdev: Ah, ok. In my Skill Rings mod, I had tried to store 30 flags each into 3 global longs. When I kept getting rounding errors, I split them each into two 15 flag shorts: safely under the limit. In the script I posted, I am using the 2^23 bit so I may have to rethink that one. It dawned on me that I worded my original post vaguely which is why you didn't answer as I expected :) I meant an array of bools vs an array of ints. I used bools because it made sense and I assumed this array would use fewer resources and possibly be faster. Obviously this is wrong so it doesn't make sense to go out of my way to use the bools instead of ints if the ints are easier to work with. You guys are great help. Thx much.
User avatar
JD bernal
 
Posts: 3450
Joined: Sun Sep 02, 2007 8:10 am

Post » Tue Nov 20, 2012 4:53 am

It dawned on me that I worded my original post vaguely which is why you didn't answer as I expected :smile: I meant an array of bools vs an array of ints. I used bools because it made sense and I assumed this array would use fewer resources and possibly be faster.
Oh! Then, while an array of bools would probably be faster in every other language, in papyrus the number of operations prevails because every operation is so slow. So basically, here, whatever makes your life easier with a simpler code will be faster anyway. ^^
User avatar
Claire Mclaughlin
 
Posts: 3361
Joined: Mon Jul 31, 2006 6:55 am

Post » Tue Nov 20, 2012 6:27 am

Oh! Then, while an array of bools would probably be faster in every other language, in papyrus the number of operations prevails because every operation is so slow. So basically, here, whatever makes your life easier with a simpler code will be faster anyway. ^^

I would say this is true, since a computer works in 1 and 0 which can in many cases be translated to true and false.
A lot of different languages (programming languages mind you, not scripting languages like Papyrus is) would work most efficiently with an array of booleans rather than integers simply because a boolean is the most pure logic a computer can comprehend, whereas an integer can be any number between -32000 ish and +32000 ish unless it's signed (i believe) then it can range from 0 to 65000 something. So to answer your question:

This is a Scripting Language and does not follow the normal logic that a programming language often do.
It could mean that Bethesda have made ints more efficient, but it could also mean booleans. All logic (See what I did there?) speaks for an array of booleans.
User avatar
Amy Siebenhaar
 
Posts: 3426
Joined: Fri Aug 10, 2007 1:51 am

Post » Tue Nov 20, 2012 10:42 am

I would say this is true, since a computer works in 1 and 0 which can in many cases be translated to true and false.
A lot of different languages (programming languages mind you, not scripting languages like Papyrus is) would work most efficiently with an array of booleans rather than integers simply because a boolean is the most pure logic a computer can comprehend, whereas an integer can be any number between -32000 ish and +32000 ish unless it's signed (i believe) then it can range from 0 to 65000 something.
This is backward. Signed means it has a plus sign or minus sign and the range, IIRC, is -32767 to 32768. Unsigned means you you don't need the highest bit to define +/- and means you can multiply the number by 2 so that range is 0 to 65535.

This is a Scripting Language and does not follow the normal logic that a programming language often do.
It could mean that Bethesda have made ints more efficient, but it could also mean booleans. All logic (See what I did there?) speaks for an array of booleans.
From the discussion here, I would guess that even booleans are stored as 32-bit floats and are casted as you need them. This is purely speculation with no solid evidence.

User avatar
Naomi Ward
 
Posts: 3450
Joined: Fri Jul 14, 2006 8:37 pm

Post » Tue Nov 20, 2012 6:51 am

This is backward. Signed means it has a plus sign or minus sign and the range, IIRC, is -32767 to 32768. Unsigned means you you don't need the highest bit to define +/- and means you can multiply the number by 2 so that range is 0 to 65535.

Yeah I was trying to remember it from the top of my head.

From the discussion here, I would guess that even booleans are stored as 32-bit floats and are casted as you need them. This is purely speculation with no solid evidence.

It sounds very strange if that was the case, but then again Bethesda make weird decisions some times...
User avatar
Deon Knight
 
Posts: 3363
Joined: Thu Sep 13, 2007 1:44 am

Post » Tue Nov 20, 2012 2:47 pm

I would say this is true, since a computer works in 1 and 0 which can in many cases be translated to true and false.
A lot of different languages (programming languages mind you, not scripting languages like Papyrus is) would work most efficiently with an array of booleans rather than integers simply because a boolean is the most pure logic a computer can comprehend, whereas an integer can be any number between -32000 ish and +32000 ish unless it's signed (i believe) then it can range from 0 to 65000 something.
For the start this premise is wrong. In C language for example, "if (someBoolean)" and "if (someInteger)" generate the same x86 code relying on the jz/jnz instructions (jump if zero/non-zero). That's it, booleans are actually numbers for the CPU. This all makes sense if you stop thinking of the CPU as a little magic box but rather as a computing unit that pulls its data from the slow memory to its cache 16 bytes at once, then from the cache to its 8 bytes registers at least one byte at once and preferably from a 8 bytes-aligned address (and you may want to read this great link: http://igoro.com/archive/gallery-of-processor-cache-effects/). Let's not even talk about RISC processors like the PS3 one or ARM architectures that tend to not have a jz/jnz specialized instructions but only jeq, jneq (jump if equal/not equal).

So what differs between bool and int arrays at the CPU level are the following:
* A boolean takes one byte, which means less memory used, which means less memory transfers and adverse cache effects.
* A boolean array requires more processing by the CPU because it needs to unpack values (remember that CPU like their things being properly aligned on 8 bytes), although asm code may look similar.
Usually this makes the boolean array faster in C/asm, but not always.

It could mean that Bethesda have made ints more efficient, but it could also mean booleans. All logic (See what I did there?) speaks for an array of booleans.
Now welcome in papyrus where extra instructions are generated all the way along. "if (someBool)" and "if (someInteger)" seem to both store the result in an extra temp variable (may not be done if someBool is a local var rather than a field or prop, I didn't check), then test the temps var, and where bool is likely to be the same size as int or float. None of them seem to have the advantage.

So from a performance's standpoint the winner is the one that makes you less write code. And from a code quality standpoint, again, the winner is the one that makes you less write code.

But, again, such performances considerations are unneeded and toxic. If someone has a performances problem, rewriting the same algorithm with different insutrctions is never the solution and always a waste of time. Possible benefits are just too ridiculous.
User avatar
DAVId Bryant
 
Posts: 3366
Joined: Wed Nov 14, 2007 11:41 pm

Post » Tue Nov 20, 2012 7:07 am

For the start this premise is wrong. In C language for example, "if (someBoolean)" and "if (someInteger)" generate the same x86 code relying on the jz/jnz instructions (jump if zero/non-zero). That's it, booleans are actually numbers for the CPU. This all makes sense if you stop thinking of the CPU as a little magic box but rather as a computing unit that pulls its data from the slow memory to its cache 16 bytes at once, then from the cache to its 8 bytes registers at least one byte at once and preferably from a 8 bytes-aligned address (and you may want to read this great link: gallery of cache effects). Let's not even talk about RISC processors like the PS3 one or ARM architectures that tend to not have a jz/jnz specialized instructions but only jeq, jneq (jump if equal/not equal).

So what differs between bool and int arrays at the CPU level are the following:
* A boolean takes one byte, which means less memory used, which means less memory transfers and adverse cache effects.
* A boolean array requires more processing by the CPU because it needs to unpack values (remember that CPU like their things being properly aligned on 8 bytes), although asm code may look similar.
Usually this makes the boolean array faster in C/asm, but not always.


Now welcome in papyrus where extra instructions are generated all the way along. "if (someBool)" and "if (someInteger)" seem to both store the result in an extra temp variable (may not be done if someBool is a local var rather than a field or prop, I didn't check), then test the temps var, and where bool is likely to be the same size as int or float. None of them seem to have the advantage.

So from a performance's standpoint the winner is the one that makes you less write code. And from a code quality standpoint, again, the winner is the one that makes you less write code.

But, again, such performances considerations are unneeded and toxic. If someone has a performances problem, rewriting the same algorithm with different insutrctions is never the solution and always a waste of time. Possible benefits are just too ridiculous.

I don't look at the CPU as a magic box...
I've had Computer Architecture and currently studying Computer Science on 3rd Semester.

I just didn't go into details as such. Just whats on the surface I guess.
User avatar
Queen of Spades
 
Posts: 3383
Joined: Fri Dec 08, 2006 12:06 pm


Return to V - Skyrim